23

In Ruby:

for i in A do
    # some code
end

is the same as:

A.each do |i|
   # some code
end

for is not a kernel method:

  • What exactly is "for" in ruby
  • Is there a way to use other keywords to do similar things?

Something like:

 total = sum i in I {x[i]}

mapping to:

 total = I.sum {|i] x[i]}
David Nehme
  • 21,379
  • 8
  • 78
  • 117

3 Answers3

46

It's almost syntax sugar. One difference is that, while for would use the scope of the code around it, each creates a separate scope within its block. Compare the following:

for i in (1..3)
  x = i
end
p x # => 3

versus

(1..3).each do |i|
  x = i
end
p x # => undefined local variable or method `x' for main:Object
sawa
  • 165,429
  • 45
  • 277
  • 381
Firas Assaad
  • 25,006
  • 16
  • 61
  • 78
  • Wow, so subtle, yet will become handy when I run into something like this. Thanks! – sivabudh Oct 08 '11 at 02:20
  • Actually your second example throws `NameError: undefined local variable or method 'i' for main:Object`. It's because you're missing a `do`. – Jakub Hampl Jan 07 '12 at 02:10
14

for is just syntax sugar for the each method. This can be seen by running this code:

for i in 1 do
end

This results in the error:

NoMethodError: undefined method `each' for 1:Fixnum
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
9

For is just syntactic sugar.

From the pickaxe:

For ... In

Earlier we said that the only built-in Ruby looping primitives were while and until. What's this ``for'' thing, then? Well, for is almost a lump of syntactic sugar. When you write

for aSong in songList
  aSong.play
end

Ruby translates it into something like:

songList.each do |aSong|
  aSong.play
end

The only difference between the for loop and the each form is the scope of local variables that are defined in the body. This is discussed on page 87.

You can use for to iterate over any object that responds to the method each, such as an Array or a Range.

for i in ['fee', 'fi', 'fo', 'fum']
  print i, " "
end
for i in 1..3
  print i, " "
end
for i in File.open("ordinal").find_all { |l| l =~ /d$/}
  print i.chomp, " "
end

produces:

fee fi fo fum 1 2 3 second third

As long as your class defines a sensible each method, you can use a for loop to traverse it.

class Periods
  def each
    yield "Classical"
    yield "Jazz"
    yield "Rock"
  end
end


periods = Periods.new
for genre in periods
  print genre, " "
end

produces:

Classical Jazz Rock

Ruby doesn't have other keywords for list comprehensions (like the sum example you made above). for isn't a terribly popular keyword, and the method syntax ( arr.each {} ) is generally preferred.

rampion
  • 87,131
  • 49
  • 199
  • 315