Reputation: 1
I need to group a hash by keys and concatenate the values. For example, given this hash:
[
{"name": "FT002", "data": {"2017-11-01": 1392.0}},
{"name": "FT004", "data": {"2017-11-01": 4091.0}},
{"name": "FT002", "data": {"2017-12-01": 1279.0}},
{"name": "FT004", "data": {"2017-12-01": 3249.0}}
]
I want to produce this hash:
[
{"name": "FT002", "data": {"2017-11-01": 1392.0, "2017-12-01": 1279.0}},
{"name": "FT004", "data": {"2017-11-01": 4091.0, "2017-12-01": 3249.0}}
]
Any help would be appreciated.
I tried various iterations of inject
, group_by
, and merge
, but can't seem to get the right result.
Upvotes: 0
Views: 139
Reputation: 110725
data.group_by { |h| h[:name] }.map do |k,arr|
{ name: k, data: arr.each_with_object({}) { |g,h| h.update(g[:data]) } }
end
#=> [{:name=>"FT002", :data=>{:"2017-11-01"=>1392.0, :"2017-12-01"=>1279.0}},
# {:name=>"FT004", :data=>{:"2017-11-01"=>4091.0, :"2017-12-01"=>3249.0}}]
The first step is to use Enumerable#group_by to produce the following hash.
data.group_by { |h| h[:name] }
#=> {"FT002"=>[
# {:name=>"FT002", :data=>{:"2017-11-01"=>1392.0}},
# {:name=>"FT002", :data=>{:"2017-12-01"=>1279.0}}
# ],
# "FT004"=>[
# {:name=>"FT004", :data=>{:"2017-11-01"=>4091.0}},
# {:name=>"FT004", :data=>{:"2017-12-01"=>3249.0}}
# ]
# }
The second step is to simply manipulate the keys and values of this hash. See Hash#update (aka merge!
).
An alternative to the second step is the following.
data.group_by { |h| h[:name] }.map do |k,arr|
{ name: k, data: arr.map { |g| g[:data].flatten }.to_h }
end
Note that this uses Hash#flatten, not Array#flatten.
Upvotes: 1
Reputation: 239382
You can accomplish this in three short one-liners, first producing a hash mapping names to data, and then producing your desired structure:
data = [
{"name":"FT002","data":{"2017-11-01":1392.0}},
{"name":"FT004","data":{"2017-11-01":4091.0}},
{"name":"FT002","data":{"2017-12-01":1279.0}},
{"name":"FT004","data":{"2017-12-01":3249.0}}
]
hash = Hash.new { |hash,key| hash[key] = {} }
data.each { |name:, data:| hash[name].merge!(data) }
hash = hash.map { |k,v| { name: k, data: v } }
Upvotes: 1
Reputation: 2169
This should generate the the results you're looking for:
data = [
{"name":"FT002","data":{"2017-11-01":1392.0}},
{"name":"FT004","data":{"2017-11-01":4091.0}},
{"name":"FT002","data":{"2017-12-01":1279.0}},
{"name":"FT004","data":{"2017-12-01":3249.0}}
]
newData = {}
data.each do |x|
newData[x[:name]] = [] unless newData[x[:name]].present?
newData[x[:name]].push x[:data]
end
combined = []
newData.each do |index,value|
dateData = {}
value.each do |dateStuff|
dateStuff.each do |dateIndex, dateValue|
dateData[dateIndex] = dateValue
end
end
values = {"name": index, "data": dateData}
combined.push values
end
combined
Upvotes: -1