2013-11-25 29 views
7

我知道for i in arrarr.each范围略有不同,每个人都说迭代器是可取的,但我不知道是否有任何情况下,当循环是可取的,为什么它是(因为迭代器更习惯)?有没有更好的选择,而不是每个Ruby?

+3

在Ruby中进行原型设计时,为了加快C语言扩展的速度,我发现使用更多C类成语有助于转换。但可能不是你正在寻找的答案。 。 。 –

+2

此评论不是作为答案,只是提供一些额外的信息。根据[这个答案](http://stackoverflow.com/a/3294543/877472),'for'和'each'在后台使用'.each'。主要区别(根据来自同一问题的这个答案)(http://stackoverflow.com/a/3294561/877472))是如何将迭代器变量作用域的。最终,除了尼尔斯莱特的帖子之外,听起来似乎没有任何技术理由可以选择比其他更好的技术。 –

回答

9

TL; DR

  • 使用for循环性能的红宝石1.8
  • 使用for循环到现有项目的标准
  • 使用each环,以尽量减少副作用
  • 身高:each环。

each最小化副作用

foreach之间的主要差别是作用域。

each函数占用一个块。块创建一个新的词法范围。这意味着在该函数范围内声明的任何变量在该函数之后将不再可用。

[1, 2, 3].each do |i| 
    a = i 
end 

puts a 
# => NameErrror: undefined local variable or method `a' for main:Object 

鉴于:

for i in [1, 2, 3] 
    a = i 
end 

puts a 
# => 3 

因此,使用each语法最小化副作用的风险。

确定退出点?

这就是说,有些特殊情况下for循环可能会有所帮助。具体来说,找出循环退出的位置。

for i in 1..3 
    a = i 

    break if i % 2 == 0 
end 

puts a 
# => 0 

有一种更好的方式来做到这一点,虽然:

a = (1..3).each do |i| 
    break i if i % 2 == 0 
end 

每一个都是(用Ruby 2.0)

Benchmark.bm(8) do |x| 
    x.report "For" do 
    max.times do 
     for i in 1..100 
     1 + 1 
     end 
    end 
    end 

    x.report "Each" do 
    max.times do 
     (1..100).each do |t| 
     1+1 
     end 
    end 
    end 
end 

红宝石2.0

   user  system  total  real 
For  6.420000 0.000000 6.420000 ( 6.419870) 
Each  5.830000 0.000000 5.830000 ( 5.829911) 

的Ruby 1.8.6(机器慢)

   user  system  total  real 
For  17.360000 0.000000 17.360000 (17.409992) 
Each  21.130000 0.000000 21.130000 (21.250754) 

基准2

如果你读了评论线索,有一个关于创造for对象VS each速度的讨论。 link provided有以下基准(尽管我已经清理了格式并修复了语法错误)。

b = 1..10e5 

Benchmark.bmbm (10) do |x| 
    x.report "each {}" do 
    b.each { |r| r + 1 } 
    end 

    x.report "each do end" do 
    b.each do |r| 
     r + 1 
    end 
    end 

    x.report "for do end" do 
    for r in b do 
     r + 1 
    end 
    end 
end 

红宝石2.0

    user  system  total  real 
each {}  0.150000 0.000000 0.150000 ( 0.144643) 
each do end 0.140000 0.000000 0.140000 ( 0.143244) 
for do end 0.150000 0.000000 0.150000 ( 0.147112) 

的Ruby 1.8.6

    user  system  total  real 
each {}  0.840000 0.000000 0.840000 ( 0.851634) 
each do end 0.730000 0.000000 0.730000 ( 0.732737) 
for do end 0.650000 0.000000 0.650000 ( 0.647186) 
+1

我明白这一点。我也知道内部Ruby转换为每个。但是我想知道是否还有什么情况会使用,而不是每个使用。 – p0deje

+0

我发现当性能问题时,'for'循环可能是有益的。在Ruby中创建对象非常昂贵,并且可能会导致循环中的性能下降,并且会有很多迭代。 – thomthom

+0

@thomthom你能提供显示这种情况的基准吗? – screenmutt

2

我已经写了几个插件SketchUp的红宝石API,我发现迭代大集合时(几何实体)我会得到更好的性能,通过一个for in循环each区块。

我认为这是因为for in循环不会创建它的本地作用域,并且对象被重用,而不是像每个迭代中创建的那样,因为它将在each循环中创建。


编辑:速度增益取决于Ruby版本。使用本文http://blog.shingara.fr/each-vs-for.html中使用的测试片段:

的Ruby 1.8.6:

   user  system  total  real 
For  14.742000 0.000000 14.742000 (14.777000) 
Each  18.190000 0.000000 18.190000 (18.194000) 

的Ruby 2.0.0

   user  system  total  real 
For  5.975000 0.000000 5.975000 ( 5.990000) 
Each  5.444000 0.000000 5.444000 ( 5.438000) 

事情大大因为旧的1.8提高。 6。 (尽管SketchUp扩展开发者仍然需要针对这个版本进行优化。)

+2

1.8.6在很久以前就跌落支撑位。它也慢了很多,所以它用于比较是可疑的。也许1.8的最终版本。7会更合理,但1.9.3会更有意义。 –

+1

诚然,如果你有控制Ruby平台。但是如果你为SketchUp编写扩展,你必须处理Ruby 1.8.6。 – thomthom

相关问题