为什么each
循环优先于Ruby中的for
循环?时间复杂度是否存在差异,或者它们在语法上是否有所不同?
答案 0 :(得分:7)
是的,这是两种不同的迭代方式,但希望这个计算有所帮助。
require 'benchmark'
a = Array( 1..100000000 )
sum = 0
Benchmark.realtime {
a.each { |x| sum += x }
}
这需要5.866932秒
a = Array( 1..100000000 )
sum = 0
Benchmark.realtime {
for x in a
sum += x
end
}
这需要6.146521秒。
虽然它不是进行基准测试的正确方法,但也存在一些其他限制。但是在一台机器上,每台机器似乎都要快一些。
答案 1 :(得分:4)
在迭代中引用项的变量是临时的,并且在迭代之外没有意义。如果从迭代之外隐藏它会更好。对于外部迭代器,此类变量位于迭代块之外。在下文中,e
仅在do
... end
内有用,但与块分开,并在其外部写入;程序员看起来并不容易:
for e in [:foo, :bar] do
...
end
使用内部迭代器,块变量在块内部定义,使用它。它更容易阅读:
[:foo, :bar].each do |e|
...
end
此可见性问题不仅适用于程序员。关于范围意义上的可见性,外部迭代器的变量可以在迭代之外访问:
for e in [:foo] do; end
e # => :foo
而在内部迭代器中,块变量在外部是不可见的:
[:foo].each do |e|; end
e # => undefined local variable or method `e'
从封装的角度来看,后者更好。
当你想嵌套循环时,变量的顺序会因外部迭代器而有些倒退:
for a in [[:foo, :bar]] do
for e in a do
...
end
end
但是使用内部迭代器,顺序更直接:
[[:foo, :bar]].each do |a|
a.each do |e|
...
end
end
使用外部迭代器,您只能使用硬编码的Ruby语法,并且还必须记住关键字与内部调用的方法之间的匹配(for
调用each
),但对于内部迭代器,您可以定义自己的迭代器,从而提供灵活性。
答案 2 :(得分:3)
each
是Ruby Way。实现具有脱钩益处的Iterator Pattern。
答案 3 :(得分:2)
一个有趣的问题。在Ruby中有几种循环方式。我已经注意到Ruby中有一个设计原则,当有多种方法可以做同样的事情时,它们之间通常会有微妙的差异,每个案例都有自己独特的用途,它解决了自己的问题。所以最后你最终需要能够写出(而不仅仅是阅读)所有这些内容。
关于for
循环的问题,这类似于my earlier question whethe for loop is a trap。
基本上有两种主要的显式循环方式,一种是通过迭代器(或者更常见的是块),例如
[1, 2, 3].each { |e| puts e * 10 }
[1, 2, 3].map { |e| e * 10 )
# etc., see Array and Enumerable documentation for more iterator methods.
连接到这种迭代方式的是类Enumerator
,您应该努力理解。
另一种方式是按while
,until
和for
循环进行Pascal-ish循环。
for y in [1, 2, 3]
puts y
end
x = 0
while x < 3
puts x; x += 1
end
# same for until loop
与if
和unless
一样,while
和until
有尾部形式,例如
a = 'alligator'
a.chop! until a.chars.last == 'g'
#=> 'allig'
第三个非常重要的循环方式是隐式循环,或者通过递归循环。 Ruby非常具有可塑性,所有类都可以修改,可以为各种事件设置钩子,这可以被利用来产生最不寻常的循环方式。可能性是无穷无尽的,我甚至不知道从哪里开始谈论它们。也许一个好地方是blog by Yusuke Endoh,一个着名的艺术家,使用Ruby代码作为他的首选艺术材料。
为了证明我的意思,请考虑这个循环
class Object
def method_missing sym
s = sym.to_s
if s.chars.last == 'g' then s else eval s.chop end
end
end
alligator
#=> "allig"
答案 4 :(得分:1)
除可读性问题外,for
循环在Ruby域中迭代,而each
在本机代码中进行迭代,因此原则上each
在迭代所有元素时应该更有效率阵列。
循环:
arr.each {|x| puts x}
循环for:
for i in 0..arr.length
puts arr[i]
end
在each
情况下,我们只是将代码块传递给在机器的本机代码(快速代码)中实现的方法,而在for
情况下,所有代码都必须被解释并运行考虑到Ruby语言的所有复杂性。
但是for
更灵活,让您以比each
更复杂的方式进行迭代,例如,使用给定步骤进行迭代。
修改强>
我没有遇到过你可以在调用each()之前使用step()方法跳过一个范围,所以我声称for
循环的灵活性实际上是不合理的。