I'd like to do the following with ruby
, but I don't know how to do it.
A {}
is taken out of a plurality of []
and stored in one []
.However, {}
with the same id
adds up the num
into one.
data1=[{
'id' = > 1,
'num' = > 1
},{
'id' = > 2,
'num' = > 3
},{
'id' = > 3,
'num' = > 5
}]
data2 = [{
'id' = > 1,
'num' = > 2
},{
'id' = > 3,
'num' = > 4
}]
data3 = [{
'id' = > 1,
'num' = > 2
},{
'id' = > 4,
'num' = > 4
}]
↓
[{
'id' = > 1,
'num' = > 5
},{
'id' = > 2,
'num' = > 3
},{
'id' = > 3,
'num' = > 9
},{
'id' = > 4,
'num' = > 4
}]
What do you think about it like this?Hash once and then back to array.
[data1,data2,data3].flatten.inject Hash.new do|a,e|
h={e['id']=>e['num']}
a. merge! hdo | k, v1, v2 |
v1+v2
end
end.inject[]do|a,e|
a<<{'id'=>e[0], 'num'=>e[1]}
end
[data1,data2,data3].flatten.each_with_object([]){|v,a|
if ev = a.detect { | ev | v [ 'id' ] == ev [ 'id' ] }
ev.merge!(v.merge('num'=>v['num']+ev['num']))
else
a<v.dup
end
}
In the example code of the question, the only hash keys were id
and num
, but
Hash keys contain or do not contain anything other than id
, num
, and
In the following sentence of the question,
However, {}s with the same id add up num and combine them into one.
num
was added together, so
data1=[{
'id' = > 1,
'num' = > 1,
'foo' = > 'bar'
},{
'id' = > 2,
'num' = > 3
},{
'id' = > 3,
'num' = > 5
}]
data2 = [{
'id' = > 1,
'num' = > 2,
'bar' = > 'buzz'
},{
'id' = > 3,
'num' = > 4
}]
data3 = [{
'id' = > 1,
'num' = > 2,
'hoge' = > 'piyo'
},{
'id' = > 4,
'num' = > 4
}]
# =>[{"id"=>1, "num"=>5, "foo"=>"bar", "bar"=>"buzz", "hoge"=>"piyo"}, {"id"=>2, "num"=>3}, {"id"=>3,9;num;"=">">{"id"=">num;">">">"
I wrote the code thinking about when the data like the one above was entered.
If the hash keys are only id and num,
[data1,data2,data3].flatten.each_with_object({}){|v,r|
r[v['id']]||=0
r[v['id']]+=v['num']
}.map { | id, num |
{'id'=>id, 'num'=>num}
}
data=[data1,data2,data3].flatten.group_by {|elem|elem['id']}
result_data=[ ]
data.each_pair do | key,arr |
sum=arr.inject(0){|memo, item|memo+item['num']}
result_data<<{'id'=>key, 'num'=>sum}
end
result_data
First of all, we will organize multiple arrays into one and classify them by id.
Then find the sum of the num for the elements in each classified group.
Finally, store the results in result_data
.
I wrote it without using temporary variables.
(data1+data2+data3)
.group_by {|h|h['id']}
.reduce([]){|memo,(k,v)|
memo<<{'id'=>k, 'num'=>v.map {|h|h['num']}.reduce(:+)}
I thought it would be fun, so I tried it.
It's a bit of a functional programming logic.
require 'minitest/autorun'
defmerge_hash(*data_list)
data_list
.flatten
.map (&:values)
.each_with_object(Hash.new(0)){|(id, num), hash|hash[id]+=num}
.map { | id, num | {'id'=>id, 'num'=>num}}
end
describe'#merge_hash'do
let(:data1)do
[{
'id' = > 1,
'num' = > 1
},{
'id' = > 2,
'num' = > 3
},{
'id' = > 3,
'num' = > 5
}]
end
let(:data2)do
[{
'id' = > 1,
'num' = > 2
},{
'id' = > 3,
'num' = > 4
}]
end
let(:data3)do
[{
'id' = > 1,
'num' = > 2
},{
'id' = > 4,
'num' = > 4
}]
end
let(:result) do
[{
'id' = > 1,
'num' = > 5
},{
'id' = > 2,
'num' = > 3
},{
'id' = > 3,
'num' = > 9
},{
'id' = > 4,
'num' = > 4
}]
end
it do
merge_hash(data1,data2,data3).must_equal result
end
end
You can do it like this.
def merge_hash(*data_list)
data_list
.flatten
.map (&:values)
.group_by (&:first)
.map {|id, items|{'id'=>id, 'num'=>items.map(&:last).inject(:+)}
end
© 2024 OneMinuteCode. All rights reserved.