Reputation: 9759
I have an array of hashes like the following:
records = [
{ id: "PU525", note: "Foo" },
{ id: "PU525", note: "Bar" },
{ id: "DT525", note: "Hello World" },
{ id: "PU680", note: "Fubar" }
]
The end result should be:
result = [
{ id: "PU525", note: "FooBar" },
{ id: "DT525", note: "Hello World" },
{ id: "PU680", note: "Fubar" }
]
I started playing a little bit with Enumerable#group_by
with the following:
results = records.group_by { |record| record[:id] }
# Results in:
# {
# "PU525": [
# { id: "PU525", note: "Foo" },
# { id: "PU525", note: "Bar" }
# ],
# "DT525": { id: "DT525", note: "Hello World" },
# "PU680": { id: "PU680", note: "Fubar" }
# }
The next step would be to use inject to reduce the data down further, but I'm wondering if there's an easier way to reduce down the original array to what I'm looking for as a result without so many steps?
Upvotes: 0
Views: 57
Reputation: 110725
Here are a couple of variants of the above.
Using Enumerable#group_by
records.group_by { |h| h[:id] }.map { |id, arr|
{ id: id, note: arr.map { |h| h[:note] }.join } }
#=> [{:id=>"PU525", :note=>"FooBar"},
# {:id=>"DT525", :note=>"Hello World"},
# {:id=>"PU680", :note=>"Fubar"}]
Using Hash#update (aka merge!
)
records.each_with_object({}) { |g,h| h.update(g[:id]=>g) { |_,og,ng|
{ id: g[:id], note: og[:note]+ng[:note] } } }.values
#=>[{:id=>"PU525", :note=>"FooBar"},
# {:id=>"DT525", :note=>"Hello World"},
# {:id=>"PU680", :note=>"Fubar"}]
Upvotes: 0
Reputation: 121000
You are nearly done:
records = [
{ id: "PU525", note: "Foo" },
{ id: "PU525", note: "Bar" },
{ id: "DT525", note: "Hello World" },
{ id: "PU680", note: "Fubar" }
]
arr = records.group_by { |record| record[:id] }
.map do |k, v|
[k, v.reduce('') { |memo, h| memo + h[:note] } ]
end
.map do |a|
{ id: a.first, note: a.last }
end
#⇒ [
# { id: "PU525", note: "FooBar" },
# { id: "DT525", note: "Hello World" },
# { id: "PU680", note: "Fubar" }
# ]
UPD After all, you have me entagled with this silly group_by
approach. Everything is just easier.
records.inject({}) do |memo, el|
(memo[el[:id]] ||= '') << el[:note]
memo
end.map { |k, v| { id: k, note: v } }
Upvotes: 3
Reputation: 118289
Here is another way, after using #group_by
:
records = [
{ id: "PU525", note: "Foo" },
{ id: "PU525", note: "Bar" },
{ id: "DT525", note: "Hello World" },
{ id: "PU680", note: "Fubar" }
]
hsh = records.group_by { |record| record[:id] }.map do |_, v|
v.inject do |h1, h2|
h1.update(h2) { |k, o, n| k == :note ? o << n : n }
end
end
p hsh
# >> [{:id=>"PU525", :note=>"FooBar"}, {:id=>"DT525", :note=>"Hello World"}, {:id=>"PU680", :note=>"Fubar"}]
Upvotes: 1