I want to combine the hash in the array into one after summing the values for each id.

Asked 2 years ago, Updated 2 years ago, 62 views

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
}]

ruby

2022-09-30 20:48

6 Answers

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


2022-09-30 20:48

[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.


2022-09-30 20:48

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}
}


2022-09-30 20:48

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.


2022-09-30 20:48

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(:+)}


2022-09-30 20:48

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


2022-09-30 20:48

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.