Is there any case to prefer for instead of each in Ruby?
ruby
Solution
TL;DR
- Use `for` loop for performance in Ruby 1.8
- Use `for` loop to standards in existing projects
- Use `each` loop to minimize side effects
- Prefer `each` loop.
`each` minimizes side effects
The primary difference between `for` and `each` is scoping.
The `each` function takes a block. Blocks create a new lexical scope. This means that any variables declared within the scope of the function will no longer be available after the function.
[1, 2, 3].each do |i|
a = i
end
puts a
# => NameErrror: undefined local variable or method `a' for main:Object
Whereas:
for i in [1, 2, 3]
a = i
end
puts a
# => 3
Thus, using the `each` syntax minimizes the risk of side effects.
Determing exit point?
This said, there are special instances where the `for` loop may be helpful. Specifically, when finding out where a loop exited.
for i in 1..3
a = i
break if i % 2 == 0
end
puts a
# => 0
There is a better way to do this though:
a = (1..3).each do |i|
break i if i % 2 == 0
end
Each is faster (in 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
Ruby 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 (Slower Machine)
user system total real
For 17.360000 0.000000 17.360000 ( 17.409992)
Each 21.130000 0.000000 21.130000 ( 21.250754)
Benchmarks 2
If you read the comment trail, there is a discussion about the speed of creating objects in `for` vs `each`. The link provided had the following benchmarks (although, I have cleaned up the formatting and fixed the syntax errors).
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
Ruby 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)
Problem
I know that `for i in arr` slightly differs from `arr.each` scope and everyone keeps saying that iterators are preferrable, but I wonder if there is any case when cycle is preferrable and why it is (since iterators are more idiomatic)?