如何基于元素值对嵌套数组中的值求和

时间:2019-07-12 16:28:15

标签: arrays ruby hash

我有一个哈希数组:

[{:metric_type=>"gender", :key=>"female", :value=>1.0},
 {:metric_type=>"gender", :key=>"male", :value=>2},
 {:metric_type=>"gender", :key=>"female", :value=>3.0},
 {:metric_type=>"gender", :key=>"male", :value=>4.0},
 {:metric_type=>"gender", :key=>"female", :value=>5.5},
 {:metric_type=>"gender", :key=>"male", :value=>6.5},
 {:metric_type=>"gender", :key=>"female", :value=>7.5},
 {:metric_type=>"gender", :key=>"male", :value=>8.5},
 {:metric_type=>"gender", :key=>"female", :value=>9},
 {:metric_type=>"gender", :key=>"male", :value=>10.5},
 {:metric_type=>"gender", :key=>"female", :value=>11},
 {:metric_type=>"gender", :key=>"male", :value=>12.5},
 {:metric_type=>"gender", :key=>"female", :value=>13.1},
 {:metric_type=>"gender", :key=>"male", :value=>14.5}]

我想遍历这些元素中的每一个,并基于分配给其他两个键:metric_type:key的值求和,并尝试获得结果看起来像这样:

[{:metric_type=>"gender", :key=>"female", :value=50.1},
{:metric_type=>"gender", :key=>"male", :value=>58.5}]

我玩过injectreduce,但无法提出我想要的东西。

4 个答案:

答案 0 :(得分:2)

让我们将您的数组命名为a

result = a.group_by { |x| x[:key] }.values.map do |v|
  v.reduce do |a, b|
    a.merge(b) do |k, v1, v2|
      k.eql?(:value) ? v1 + v2 : v1
    end
  end
end

p result

输出

[{:metric_type=>"gender", :key=>"female", :value=>50.1}, {:metric_type=>"gender", :key=>"male", :value=>58.5}]

答案 1 :(得分:0)

可能有一些有趣的单行解决方案,但是我认为这足够简短且可读。假设您的哈希数组命名为arr

females = {:metric_type=>"gender", :key=>"female", :value=>0.0} 
males = {:metric_type=>"gender", :key=>"male", :value=>0.0} 

arr.each_with_object([females, males]) do |hsh|
  males[:value] += hsh[:value] if hsh[:key] == "male"
  females[:value] += hsh[:value] if hsh[:key] == "female"
end

很明显,这仅在您仅支持示例中列出的两个key的情况下有效。如果可能还有其他答案,则需要使用其他答案之一。

答案 2 :(得分:0)

如果arr保存了数组,则有两种方法。

使用Enumerable#partitionHash#merge

arr.partition { |h| h[:key]=="female" }.
    map do |a|
      tot = a.sum { |h| h[:value] }
      a.first.merge(value: tot)
    end
  #=> [{:metric_type=>"gender", :key=>"female", :value=>50.1},
  #    {:metric_type=>"gender", :key=>"male", :value=>58.5}] 

使用Hash#update(也称为merge!)和Hash#merge的形式,它们采用一个块来确定要合并的两个哈希中存在的键的值。

arr.each_with_object({}) do |g,h|
  h.update(g[:key]=>g) do |_,o,n|
    o.merge(n) { |k,oo,nn| k==:value ? (oo+nn) : oo }
  end
end

答案 3 :(得分:0)

如果您使用的是最新的Ruby(或使用Rails),则可以:

array.group_by { |x| x[:key] }.map do |key, collection|
  collection.first.merge(value: collection.sum { |x| x[:value] })
end
# => [{:metric_type=>"gender", :key=>"female", :value=>50.1}, 
#     {:metric_type=>"gender", :key=>"male", :value=>58.5}]

老红宝石,您可以这样做:

array.group_by { |x| x[:key] }.map do |key, collection|
  collection.first.merge(value: collection.map { |x| x[:value] }.inject(:+))
end
# => [{:metric_type=>"gender", :key=>"female", :value=>50.1}, 
#     {:metric_type=>"gender", :key=>"male", :value=>58.5}]