cozyconemotel
cozyconemotel

Reputation: 1161

Loop collapsing in Ruby - iterating through combinations of two ranges

I have a code that iterates through two ranges. Please see the example below:

(0..6).each do |wday|
  (0..23).each do |hour|
    p [wday,hour]
  end
end

Although this seems very concise and readable, sometimes 5 lines can be too much. One might want to write a more vertically compact code.

(0..6).to_a.product((0..23).to_a).each do |wday,hour|
  p [wday, hour]
end

Above was my try, but the code looks very artificial to me. Am I missing something? Does ruby have a preferred way for this type of loop collapsing? If not, are there other alternatives to this workaround?

Upvotes: 2

Views: 76

Answers (1)

Neil Slater
Neil Slater

Reputation: 27207

The following is slightly cleaner version of your loop:

[*0..6].product([*0..23]).each do |wday,hour|
  p [wday, hour]
end

This approach does have the disadvantage of expanding the ranges into memory.

I think my preferred way of "collapsing" loops though, especially if the specific loop structure occurs in multiple places, is to turn the nested loops into a method that takes a block and yields to it. E.g.

def for_each_hour_in_week
  (0..6).each do |wday|
    (0..23).each do |hour|
      yield wday,hour
    end
  end
end

for_each_hour_in_week do |wday,hour|
  p [wday,hour]
end

This keeps the deep nesting out of the way of your logic, and makes your intent clear.

Upvotes: 4

Related Questions