Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby hash combinations

For an e-commerce app, I'm trying to turn a hash of options, each with an array of choices, into an array of hashes representing the combinations of those choices. For example:

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

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

Input may have additional options inside of it with an undetermined number of choices for each one, but it will only ever be nested 1 level deep. Any

like image 596
dvanderb Avatar asked Sep 03 '14 20:09

dvanderb


2 Answers

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}]
like image 98
Cary Swoveland Avatar answered Sep 28 '22 04:09

Cary Swoveland


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"}
]
like image 35
BroiSatse Avatar answered Sep 28 '22 02:09

BroiSatse