Reputation: 10318
I just had a quick question regarding loops in Ruby. Is there a difference between these two ways of iterating through a collection?
# way 1
@collection.each do |item|
# do whatever
end
# way 2
for item in @collection
# do whatever
end
Just wondering if these are exactly the same or if maybe there's a subtle difference (possibly when @collection
is nil).
Upvotes: 233
Views: 298510
Reputation: 4996
Two pieces of simple example code will explain it well:
for i in 1..6
str1 = 'kkkk'
end
puts i # 6
puts str1 # kkkk
(1..6).each do |j|
str2 = 'kkkk'
end
# puts j # Runtime Error: undefined local variable or method `j' for main:Object (NameError)
# puts str2 # Runtime Error: undefined local variable or method `str2' for main:Object (NameError)
So I will go with .each
Upvotes: 0
Reputation: 1100
async
.require 'async'
Async do
for i in 5.times do
Async do
sleep(1)
print(i.to_s + " ")
end
end
end
Will return: 4 4 4 4 4
as i
is not re-defined for every iteration.
require 'async'
Async do
5.times.each do |i|
Async do
sleep(1)
print(i.to_s + " ")
end
end
end
Will return: 0 1 2 3 4
as i
only ever lives inside the scope of its iteration's block.
The reason for this becomes fairly obvious when reading the other answers, but since online searches for this kind of problem with async
in the query don't return any results mentioning this I left this answer here.
Do not use for .. in ..
in conjunction with async
!
Upvotes: 0
Reputation: 12092
One more difference:
number = ["one", "two", "three"]
=> ["one", "two", "three"]
loop1 = []
loop2 = []
number.each do |c|
loop1 << Proc.new { puts c }
end
=> ["one", "two", "three"]
for c in number
loop2 << Proc.new { puts c }
end
=> ["one", "two", "three"]
loop1[1].call
two
=> nil
loop2[1].call
three
=> nil
source: http://paulphilippov.com/articles/enumerable-each-vs-for-loops-in-ruby
for more clear: http://www.ruby-forum.com/topic/179264#784884
Upvotes: 7
Reputation: 27793
Never ever use for
it may cause almost untraceable bugs.
Don't be fooled, this is not about idiomatic code or style issues. Ruby's implementation of for
has a serious flaw and should not be used.
Here is an example where for
introduces a bug,
class Library
def initialize
@ary = []
end
def method_with_block(&block)
@ary << block
end
def method_that_uses_these_blocks
@ary.map(&:call)
end
end
lib = Library.new
for n in %w{foo bar quz}
lib.method_with_block { n }
end
puts lib.method_that_uses_these_blocks
Prints
quz
quz
quz
Using %w{foo bar quz}.each { |n| ... }
prints
foo
bar
quz
Why?
In a for
loop the variable n
is defined once and only and then that one definition is use for all iterations. Hence each blocks refer to the same n
which has a value of quz
by the time the loop ends. Bug!
In an each
loop a fresh variable n
is defined for each iteration, for example above the variable n
is defined three separate times. Hence each block refer to a separate n
with the correct values.
Upvotes: 8
Reputation: 992
(1..4).each { |i|
a = 9 if i==3
puts a
}
#nil
#nil
#9
#nil
for i in 1..4
a = 9 if i==3
puts a
end
#nil
#nil
#9
#9
In 'for' loop, local variable is still lives after each loop. In 'each' loop, local variable refreshes after each loop.
Upvotes: 1
Reputation: 9427
I just want to make a specific point about the for in loop in Ruby. It might seem like a construct similar to other languages, but in fact it is an expression like every other looping construct in Ruby. In fact, the for in works with Enumerable objects just as the each iterator.
The collection passed to for in can be any object that has an each iterator method. Arrays and hashes define the each method, and many other Ruby objects do, too. The for/in loop calls the each method of the specified object. As that iterator yields values, the for loop assigns each value (or each set of values) to the specified variable (or variables) and then executes the code in body.
This is a silly example, but illustrates the point that the for in loop works with ANY object that has an each method, just like how the each iterator does:
class Apple
TYPES = %w(red green yellow)
def each
yield TYPES.pop until TYPES.empty?
end
end
a = Apple.new
for i in a do
puts i
end
yellow
green
red
=> nil
And now the each iterator:
a = Apple.new
a.each do |i|
puts i
end
yellow
green
red
=> nil
As you can see, both are responding to the each method which yields values back to the block. As everyone here stated, it is definitely preferable to use the each iterator over the for in loop. I just wanted to drive home the point that there is nothing magical about the for in loop. It is an expression that invokes the each method of a collection and then passes it to its block of code. Hence, it is a very rare case you would need to use for in. Use the each iterator almost always (with the added benefit of block scope).
Upvotes: 0
Reputation: 116187
See "The Evils of the For Loop" for a good explanation (there's one small difference considering variable scoping).
Using each
is considered more idiomatic use of Ruby.
Upvotes: 54
Reputation: 10086
Your first example,
@collection.each do |item|
# do whatever
end
is more idiomatic. While Ruby supports looping constructs like for
and while
, the block syntax is generally preferred.
Another subtle difference is that any variable you declare within a for
loop will be available outside the loop, whereas those within an iterator block are effectively private.
Upvotes: 36
Reputation: 176675
This is the only difference:
each:
irb> [1,2,3].each { |x| }
=> [1, 2, 3]
irb> x
NameError: undefined local variable or method `x' for main:Object
from (irb):2
from :0
for:
irb> for x in [1,2,3]; end
=> [1, 2, 3]
irb> x
=> 3
With the for
loop, the iterator variable still lives after the block is done. With the each
loop, it doesn't, unless it was already defined as a local variable before the loop started.
Other than that, for
is just syntax sugar for the each
method.
When @collection
is nil
both loops throw an exception:
Exception: undefined local variable or method `@collection' for main:Object
Upvotes: 343
Reputation: 10150
It looks like there is no difference, for
uses each
underneath.
$ irb
>> for x in nil
>> puts x
>> end
NoMethodError: undefined method `each' for nil:NilClass
from (irb):1
>> nil.each {|x| puts x}
NoMethodError: undefined method `each' for nil:NilClass
from (irb):4
Like Bayard says, each is more idiomatic. It hides more from you and doesn't require special language features. Per Telemachus's Comment
for .. in ..
sets the iterator outside the scope of the loop, so
for a in [1,2]
puts a
end
leaves a
defined after the loop is finished. Where as each
doesn't. Which is another reason in favor of using each
, because the temp variable lives a shorter period.
Upvotes: 2
Reputation: 18375
As far as I know, using blocks instead of in-language control structures is more idiomatic.
Upvotes: 0