user2562153
user2562153

Reputation: 317

Building varying levels of nested loops

I have an array to give a set of ranges like range = [[10,15], [7,13], [2,3]..]. I have nested iteration blocks using these ranges like below.

(10..15).each{|i|
  (7..13).each{|j|
    (2..3).each{|k|
        puts "#{k} - #{j} - #{i}"
      }
    }
 }

I have to form these nested loops dynamically based on size of the range array's size and their elements. I guess I should dynamically define a method by framing above iterations block and call the method to do the job. But I am not able to code this. Your help is much appreciated.

Upvotes: 3

Views: 84

Answers (2)

falsetru
falsetru

Reputation: 368944

Using Array#product:

range = [[10, 15], [7, 13], [2, 3]]
range = range.map { |a,b| (a..b).to_a }
# range is now `[[10, 11, 12, 13, 14, 15], [7, 8, 9, 10, 11, 12, 13], [2, 3]]`
range[0].product(*range[1..-1]) { |xs|
  puts xs.join(' - ')
}

output:

10 - 7 - 2
10 - 7 - 3
10 - 8 - 2
...
15 - 12 - 3
15 - 13 - 2
15 - 13 - 3

UPDATE according to OP's comment. If you use older version of ruby that does not have Array#product, use following:

class Array
  def product(*others)
    if others.empty?
      each {|x| yield [x] }
    else
      each {|x| others[0].product(*others[1..-1]) { |ys| yield [x] + ys }}
    end
  end
end

Upvotes: 3

shivam
shivam

Reputation: 16506

range = [[10,15], [7,13], [3,2]]
count = 0
str = ''
def dyn_levels(count, range)
    (range[count][0]..range[count][1]).each do |i|
        str.insert(str.size,i)
        if count < range.size
          str.insert(str.size,'-')
          count+=1
          dyn_level(count, range)
        end
    end
end
str.reverse!

Upvotes: 0

Related Questions