mportiz08
mportiz08

Reputation: 10318

"for" vs "each" in Ruby

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

Answers (11)

Lane
Lane

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

confetti
confetti

Reputation: 1100

This is very important when using Ruby's 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

Mr. Black
Mr. Black

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

akuhn
akuhn

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

Kelvin Tan
Kelvin Tan

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

Daniel Viglione
Daniel Viglione

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

ChristopheD
ChristopheD

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

Bayard Randel
Bayard Randel

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

Paige Ruten
Paige Ruten

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

BaroqueBobcat
BaroqueBobcat

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

Jonathan Sterling
Jonathan Sterling

Reputation: 18375

As far as I know, using blocks instead of in-language control structures is more idiomatic.

Upvotes: 0

Related Questions