Reputation: 7100
I have an array as follows:
my_array = [
[1426049999000, "Apple", 2.7235],
[1426049999000, "Orange", 2.942],
[1424235599000, "Apple", 1.124],
[1424235599000, "Orange", 1.115]
]
I want either a hash of hashes:
{
:"Apple" => {1426049999000 => 2.7235, 1424235599000 => 1.124},
:"Orange" => {1426049999000 => 2.942, 1424235599000 => 1.115}
}
or a hash of arrays:
{
:"Apple" => [[1426049999000, 2.7235], [1424235599000, 1.124]],
:"Orange" => [[1426049999000, 2.942], [1424235599000, 1.115]]
}
How can I create a nested hash or a hash of arrays that I want?
I tried:
my_array.group_by { |s| s[1] }
Output received:
{
:"Apple" => [[1426049999000, "Apple", 2.7235], [1424235599000, "Apple", 1.124]],
:"Orange" => [[1426049999000, "Orange", 2.942], [1424235599000, "Orange", 1.115]]
}
Upvotes: 0
Views: 515
Reputation: 13901
p my_array.group_by{|x| x.delete_at(1)} #=> {"Apple"=>[[1426049999000, 2.7235], [1424235599000, 1.124]], "Orange"=>[[1426049999000, 2.942], [1424235599000, 1.115]]}
# or my_array.map(&:rotate).group_by(&:shift)
Upvotes: 0
Reputation: 110675
My friend @Arup has pointed out that my latter (original) expression did not return the result requested by the OP. That is true, but it would have been more accurate to say that, since I offered two ways of returning the same result (a hash whose values were arrays of hashes), neither expression returned the requested result.
In any event, I modified my original answer to conform to the OP's instructions, and wish to thank Arup for his eagle-eye.
my_array = [[1426, "Apple", 2.723],
[1426, "Orange", 2.942],
[1424, "Apple", 1.124],
[1424, "Orange", 1.115]]
Expression #1
To produce a hash with values that are hashes:
my_array.each_with_object({}) { |(v1,fruit,v2),h|
h.update(fruit.to_sym => {v1=>v2}) { |_,ov,nv| ov.update(nv) } }
#=> {:Apple=>{1426=>2.723, 1424=>1.124},
# :Orange=>{1426=>2.942, 1424=>1.115}}
or with values that are arrays of arrays:
my_array.each_with_object({}) { |(v1,fruit,v2),h|
h.update(fruit.to_sym => [[v1, v2]]) { |_,ov,nv| ov+nv } }
#=> {:Apple=> [[1426, 2.723], [1424, 1.124]],
# :Orange=>[[1426, 2.942], [1424, 1.115]]}
I would suggest the latter, in the event that [1424, "Apple", 1.124]
in my_array
were instead, say, [1426, "Apple", 1.124]
, there would not be a problem of 1426
being a duplicate key.
Expression #2
my_array.each_with_object(Hash.new {|h,k| h[k]=[]}) { |(v1,fruit,v2),h|
h[fruit.to_sym] << [v1,v2] }
#=> {:Apple=> [[1426, 2.723], [1424, 1.124]],
# :Orange=>[[1426, 2.942], [1424, 1.115]]}
Upvotes: 1
Reputation: 80065
groups = { :"Apple" => [[1426049999000, "Apple", 2.7235], [1424235599000, "Apple", 1.124]],
:"Orange" => [[1426049999000, "Orange", 2.942], [1424235599000, "Orange", 1.115]]}
groups.each{|k,v| v.each{|ar| ar.delete(k.to_s)}}
p groups # => {:Apple=>[[1426049999000, 2.7235], [1424235599000, 1.124]], :Orange=>[[1426049999000, 2.942], [1424235599000, 1.115]]}
Upvotes: 0
Reputation: 118271
I'd do :
my_array = [[1426049999000, "Apple", 2.7235], [1426049999000, "Orange", 2.942], [1424235599000, "Apple", 1.124], [1424235599000, "Orange", 1.115]]
my_array.each_with_object({}) { |a, h| (h[a[1]] ||= []) << a.values_at(0, 2) }
# => {"Apple"=>[[1426049999000, 2.7235], [1424235599000, 1.124]], "Orange"=>[[1426049999000, 2.942], [1424235599000, 1.115]]}
my_array.each_with_object({}) { |a, h| (h[a[1]] ||= {}).update(a[0] => a[2]) }
# => {"Apple"=>{1426049999000=>2.7235, 1424235599000=>1.124}, "Orange"=>{1426049999000=>2.942, 1424235599000=>1.115}}
Upvotes: 2