"1"}, {"b"=>"2"}, {"a"=>"3"}, {"b"=>"4"}, {"a"=>"5"}] I would like th...">

Join shared keys in single-line mode

I have this array of pairs:

[{"a"=>"1"}, {"b"=>"2"}, {"a"=>"3"}, {"b"=>"4"}, {"a"=>"5"}] 

I would like the method to combine the keys along with several values:

 [{"a"=>["1","3","5"]}, {"b"=>["2","4"]}] 
+7
source share
5 answers

Improved after a proposal by Marc-Andre.

 array = [{"a"=>"1"}, {"b"=>"2"}, {"a"=>"3"}, {"b"=>"4"}, {"a"=>"5"}] array.group_by(&:keys).map{|k, v| {k.first => v.flat_map(&:values)}} 

or

 array.group_by{|h| h.keys.first}.each_value{|a| a.map!{|h| h.values.first}} 
+4
source

Not tried yet, but something like this should work too

  a.each_with_object( Hash.new{ |h,k| h[k] = [] } ) do |x, hash| hash[x.keys.first] << x.values.first end 

edit: for one liner and the same output:

 [a.each_with_object( Hash.new{ |h,k| h[k] = [] } ) { |x, hash| hash[x.keys.first] << x.values.first }] 
+1
source

The solution to your problem:

 array.map(&:first).group_by(&:first).map{|k, v| {k => v.map(&:last)}} 

I am curious why you start and end hashes containing only one key pair. Arrays are better suited. For example:.

 other = [["a", "1"], ["b", "2"], ["a", "3"], ["b", "4"], ["a", "5"]] r = other.group_by(&:first).map{|k, v| [k => v.map(&:last)]} r # => [["a", ["1", "3", "5"]], ["b", ["2", "4"]]] Hash[r] # => {"a"=>["1", "3", "5"], "b"=>["2", "4"]} 
+1
source
 array = [{"a"=>"1"}, {"b"=>"2"}, {"a"=>"3"}, {"b"=>"4"}, {"a"=>"5"}] {}.tap{ |r| array.each{ |h| h.each{ |k,v| (r[k]||=[]) << v } } } 
0
source

Not sure if you give out awards for brevity, but I like it. The block merge function is ideal for this:

 new = {} array.each {|p| new.merge!(p) {|k,l,r| [l,r].flatten }} 
0
source

All Articles