What is the preferred loop method in Ruby?

Why is each loop preferable in a for loop in Ruby? Is there a difference in time complexity or are they just syntactically different?

+7
ruby for-loop each
source share
5 answers

Yes, these are two different ways of repeating, but I hope this calculation helps.

 require 'benchmark' a = Array( 1..100000000 ) sum = 0 Benchmark.realtime { a.each { |x| sum += x } } 

It takes 5.866932 sec.

 a = Array( 1..100000000 ) sum = 0 Benchmark.realtime { for x in a sum += x end } 

It takes 6.146521 sec.

Although this is not the right way to benchmark, there are other limitations. But on one machine, each seems a little faster than for.

+7
source share
  • A variable that refers to an element in an iteration is temporary and does not matter outside the iteration. It is better if it is hidden outside the iteration. With external iterators, such a variable is located outside the iteration block. In what follows, e is only useful within do ... end , but is separated from the block and written outside of it; it doesn't look like just a programmer:

     for e in [:foo, :bar] do ... end 

    With internal iterators, a block variable is defined right inside the block where it is used. Easier to read:

     [:foo, :bar].each do |e| ... end 
  • This visibility problem is not just for the programmer. As for visibility in terms of scope, the variable for the external iterator is available outside the iteration:

     for e in [:foo] do; end e # => :foo 

    whereas in the internal iterator the block variable is invisible from the outside:

     [:foo].each do |e|; end e # => undefined local variable or method `e' 

    The latter is better in terms of encapsulation.

  • If you want to nest loops, the order of the variables will be somewhat inverse using external iterators:

     for a in [[:foo, :bar]] do for e in a do ... end end 

    but with internal iterators, the order is simpler:

     [[:foo, :bar]].each do |a| a.each do |e| ... end end 
  • With external iterators, you can only use hard-coded Ruby syntax, and also remember the correspondence between the keyword and the internal method call ( for calls each ), but for internal iterators, you can define your own, which gives flexibility.

+4
source share

each is Ruby's way. Implements an iterator pattern that has the benefits of decoupling.

Check also: "for" vs "everyone" in Ruby

+3
source share

Interest Ask. There are several ways to loop in Ruby. I noted that in Ruby there is a development principle where there are many ways to do the same, there are usually subtle differences between them, and each case has its own unique use, its own problem, which it solves. Therefore, in the end, you need to write (and not just read) all of them.

Regarding the for loop question, this is similar to my earlier question, because the loop is a trap .

Basically, there are two main explicit methods of cyclization: one of them is iterators (or, more generally, blocks), such as

 [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. 

Connected to this iteration method is the Enumerator class, which you should try to understand.

Another way is to loop Pascal-ish using while , until and for loops.

 for y in [1, 2, 3] puts y end x = 0 while x < 3 puts x; x += 1 end # same for until loop 

Like if and unless , while and until have a tail shape such as

 a = 'alligator' a.chop! until a.chars.last == 'g' #=> 'allig' 

The third very important way to loop is an implicit loop, or a loop through recursion. Ruby is extremely flexible, all classes can be changed, hooks can be customized for various events, and this can be used to create the most unusual ways to loop. The possibilities are so endless that I don’t even know where to start talking about them. Perhaps a good place is the blog post by Yusuke Endoh , a renowned artist working with Ruby code as his own piece of art of choice.

To demonstrate what I mean, consider this cycle

 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" 
+2
source share

In addition to readability issues, the for loop iterates on Ruby land, while each does this from its own code, so in principle, each should be more efficient at repeating all the elements in the array.

Loop with each:

 arr.each {|x| puts x} 

Loop for:

 for i in 0..arr.length puts arr[i] end 

In the case of each we simply pass the code block to the method implemented in the machine’s own code (fast code), while in the case of for all the code must be interpreted and executed taking into account all the complexity of the Ruby language.

However, for is more flexible and allows you to iterate in more complex ways than each does, for example, iterate with a given step.

EDIT

I have not come across the fact that you can step over a range using the step () method before calling each (), so the flexibility that I claimed for the for loop is actually unreasonable.

+1
source share

All Articles