Suppose I have an array of arrays like [[A, B, C][1,2,3]] I can easily make a hash (using each_with_index) where one value is the lookup value for the other value: 1=>A 2=>B 3=>C Now suppose I have a AoA like [[A, B, C,][1,2,2]] Is there a readable way to construct a hash like 1=>[A] 2=>[B, C] ? Thanks, -Chris

on 2005-11-30 23:59

on 2005-12-01 00:24

On Wed, 30 Nov 2005 21:57:00 -0000, Chris McMahon <removed_email_address@domain.invalid> wrote: > > > Thanks, > -Chris > I assumed you meant [['A', 'B', 'C'],[1,2,2]] - I know comma at end can be valid syntax but not sure if it fits here? If so, this seems to work: a = [['A', 'B', 'C'],[1,2,2]] h = {} a[1].each_with_index { |it, i| (h[it] ||= []) << a[0][i] } p h # => {1=>["A"], 2=>["B", "C"]}

on 2005-12-01 00:28

On Nov 30, 2005, at 4:57 PM, Chris McMahon wrote: > Now suppose I have a AoA like > > [[A, B, C,][1,2,2]] > > Is there a readable way to construct a hash like > > 1=>[A] > 2=>[B, C] input = [[:A, :B, :C],[1,2,2]] output = {} input[1].each_with_index { |group, index| (output[group] ||= []) << input[0][index] } puts "input: #{input.inspect}" puts "output: #{output.inspect}"

on 2005-12-01 00:32

Quoting Chris McMahon <removed_email_address@domain.invalid>: > 3=>C def build( values, keys ) hash = {} values.zip( keys ) do |value, key| hash[key] = value end hash end build(*[[A, B, C], [1, 2, 3]]) #=> {1=>A, 2=>B, 3=>C} > Now suppose I have a AoA like > > [[A, B, C,][1,2,2]] > > Is there a readable way to construct a hash like > > 1=>[A] > 2=>[B, C] def build2( values, keys ) hash = {} values.zip( keys ) do |value, key| ( hash[key] ||= [] ).push value end hash end build2(*[[A, B, C], [1, 2, 2]]) #=> {1=>[A], 2=>[B, C]} In other words, you can probably just take the code you've got and replace: hash[key] = value with: ( hash[key] ||= [] ).push value This bit can also be written in longer form as: hash[key] ||= [] hash[key].push value or even: hash[key] = [] unless hash[key] hash[key].push value (but the shortest form saves you one or two hash lookups) -mental

on 2005-12-01 00:48

On 11/30/05, Chris McMahon <removed_email_address@domain.invalid> wrote: > > > Thanks, > -Chris > Here's another way: a = [['A', 'B', 'C'],[1,2,3]] h = Hash[*a[0].zip(a[1]).flatten] p h -- OUTPUT -- {"A"=>1, "B"=>2, "C"=>3} Regards, Sean

on 2005-12-01 01:08

Here's a construct I use quite frequently: hsh = Hash.new{ |hh,kk| hh[kk] = Array.new } What this does is that the default value of hsh[somekey] is a new array. So, with that, we can do this: a = [['a', 'b', 'c'],[1,2,2]] hsh = Hash.new{ |hh,kk| hh[kk] = Array.new } a[0].each_index{ |ii| hsh[ a[1][ii] ].push( a[0][ii] ) } hsh => {1=>["a"], 2=>["b", "c"]}

on 2005-12-01 01:16

Oops - I didn't read the full message properly. Here really is a way to achieve what you're after (though whether it is readable or not is moot :) a = [['A', 'B', 'C'],[1,2,2]] h = a[1].zip(a[0]).inject(Hash.new{|h, k| h[k] = Array.new}) {|h, k| h[k[0]] << k[1]; h } p h -- OUTPUT -- {1=>["A"], 2=>["B", "C"]} Regards, Sean

on 2005-12-01 02:05

Hi -- On Thu, 1 Dec 2005, Chris McMahon wrote: > > Now suppose I have a AoA like > > [[A, B, C,][1,2,2]] > > Is there a readable way to construct a hash like > > 1=>[A] > 2=>[B, C] Here's an inject-based way: a.zip(b).inject({}) do |hash,(key,value)| (hash[value] ||= []) << key hash end David

on 2005-12-01 03:09

Firstly, you can use Array#zip instead of each_with_index: h = {} [1,2,3].zip([:a, :b, :c]){|key, value| h[key] = value } h => {1=>:a, 2=>:b, 3=>:c} Secondly, here is the answer h = {} [1, 2, 2].zip([:a, :b, :c]){|key, value| h[key] ||= []; # if key not defined, make it [] h[key]<<value } h => {1=>[:a], 2=>[:b, :c]} You can also combine the two lines in (h[key] ||= []) << value

on 2005-12-01 15:14

removed_email_address@domain.invalid wrote: > > def build2( values, keys ) > hash = {} > values.zip( keys ) do |value, key| > ( hash[key] ||= [] ).push value > end > hash > end > > build2(*[[A, B, C], [1, 2, 2]]) #=> {1=>[A], 2=>[B, C]} The other interesting way is def build3(values, keys) hash = Hash.new {|h,k| h[k] = []} values.zip(keys) do |value, key| hash[key].push value end hash end i.e. pushing the responsibility of generating a [] the first time a key is seen off onto the hash rather than the insertion code. martin

on 2005-12-01 23:59

David A. Black wrote: > a.zip(b).inject({}) do |hash,(key,value)| > (hash[value] ||= []) << key > hash > end or, using Hash's default initializer: hash = Hash.new {|h, k| h[k] = [] } a.zip(b).inject(hash) do |h, (k, v)| h << k end Cheers, Dave

on 2005-12-02 01:12

On 11/30/05, Chris McMahon <removed_email_address@domain.invalid> wrote: [snip] > I can easily make a hash (using each_with_index) where one value is > the lookup value for the other value: #invert can sometimes be useful.. but not in this case Hash[*%w(a b c).zip([1, 2, 2]).flatten].invert #=> {1=>"a", 2=>"c"}