我有一个哈希数组:
[{: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}]
我玩过inject
和reduce
,但无法提出我想要的东西。
答案 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#partition和Hash#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}]