Ruby way instead of for loop in specific case of array iteration

68 views Asked by At

Coming from other languages where for loop is predominant way of iterating, I am curious is there a better more Ruby style way to achieve below:

q=[5,1,7,9,0,3,6,8,0]

for i in 0..q.size/3-1

  do one thing with q[0+i*3]

  do another one with q[1+i*3]

  third operation on q[2+i*3]

end

THX!

Code submitted in question actually works, but knowing that for in Ruby uses each under the hood, I am not sure what is the best way to make it more compact&efficient.

2

There are 2 answers

3
Jörg W Mittag On BEST ANSWER

The most Ruby way to do this would probably be to use Enumerable#each_slice:

q.each_slice(3) do |first, second, third|
  # do something with `first`
  # do another thing with `second`
  # third operation with `third`
end

For example:

q.each_slice(3) do |first, second, third|
  p({ first:, second:, third: })
end
# { first: 5, second: 1, third: 7 }
# { first: 9, second: 0, third: 3 }
# { first: 6, second: 8, third: 0 }

In general, one of the most important operations in any program is "iterating over stuff" (or more generally, traversing, transforming, filtering, building, and folding collections), and in Ruby, that is handled by the Enumerable mixin. Studying and understanding this mixin's documentation is crucial to writing good, idiomatic Ruby code.

As a (slightly exaggerated) general rule, if you have to write a loop or manually fiddle with indices or counters in Ruby, you are very likely doing something wrong. In fact, with the powerful algorithms, data structures, and collections libraries that are shipped with most modern programming languages, that does not just apply to Ruby but almost universally.

0
user229044 On

As already pointed out, each_slice is pretty much the ideal answer here.

However if you were purely interested in looping over the numeric indices, transforming the code you have into something more idiomatically Ruby, you might use a range and step to move forwards by in increments of 3:

q=[5,1,7,9,0,3,6,8,0]

(0..q.size - 1).step(3) do |i|
  a = q[i]
  b = q[i + 1]
  c = q[i + 2]

  p [a, b, c]
end

# [5, 1, 7]
# [9, 0, 3]
# [6, 8, 0]