Ruby hash combinations

A variant on the above:

input = { color: [ "blue", "grey" ],
          size:  [ "s", "m", "l" ],
          wt:    [:light, :heavy] }

keys = input.keys
  #=> [:color, :size, :wt]
values = input.values
  #=> [["blue", "grey"], ["s", "m", "l"], [:light, :heavy]]
values.shift.product(*values).map { |v| Hash[keys.zip(v)] }
  #=> [{:color=>"blue", :size=>"s", :wt=>:light},
  #    {:color=>"blue", :size=>"s", :wt=>:heavy},
  #    {:color=>"blue", :size=>"m", :wt=>:light},
  #    {:color=>"blue", :size=>"m", :wt=>:heavy},
  #    {:color=>"blue", :size=>"l", :wt=>:light},
  #    {:color=>"blue", :size=>"l", :wt=>:heavy},
  #    {:color=>"grey", :size=>"s", :wt=>:light},
  #    {:color=>"grey", :size=>"s", :wt=>:heavy},
  #    {:color=>"grey", :size=>"m", :wt=>:light},
  #    {:color=>"grey", :size=>"m", :wt=>:heavy},
  #    {:color=>"grey", :size=>"l", :wt=>:light},
  #    {:color=>"grey", :size=>"l", :wt=>:heavy}]

You can try:

ary = input.map {|k,v| [k].product v}
output = ary.shift.product(*ary).map {|a| Hash[a]}

Result:

[
  {:color=>"blue", :size=>"s"},
  {:color=>"blue", :size=>"m"},
  {:color=>"blue", :size=>"l"},
  {:color=>"grey", :size=>"s"},
  {:color=>"grey", :size=>"m"},
  {:color=>"grey", :size=>"l"}
]

You're basically trying to compute combinations here, and that means two levels of iteration with a way of aggregating the results of those operations:

input = {:color=>["blue", "grey"], :size=>["s", "m", "l"]}

combinations = input[:color].flat_map do |color|
  input[:size].collect do |size|
    { color: color, size: size }
  end
end

puts combinations.inspect
# => [{:color=>"blue", :size=>"s"}, {:color=>"blue", :size=>"m"}, {:color=>"blue", :size=>"l"}, {:color=>"grey", :size=>"s"}, {:color=>"grey", :size=>"m"}, {:color=>"grey", :size=>"l"}]

Here flat_map comes in handy as it collapses the results of the inner expansion.