我在这篇文章中看到了这段代码,因为我试图根据一些标准对哈希数组中的值进行求和。
Rails sum values in an array of hashes
array = [
{loading: 10, avg: 15, total: 25 },
{loading: 20, avg: 20, total: 40 },
{loading: 30, avg: 25, total: 55 }
]
sum = Hash.new(0)
array.each_with_object(sum) do |hash, sum|
hash.each { |key, value| sum[key] += value }
end
# => {:loading=>60, :avg=>60, :total=>120}
我正在尝试做什么而且我不知道怎样,如果在此数组中加载和avg在同一个值中出现多次相同的值,那么总和是否总和。例如。
array = [
{loading: 10, avg: 15, total: 25 },
{loading: 20, avg: 20, total: 40 }, # See here
{loading: 30, avg: 25, total: 55 },
{loading: 20, avg: 20, total: 80 }, # See here
{loading: 10, avg: 20, total: 46 }
]
结果将是:
[
{loading: 10, avg: 15, total: 25 },
{loading: 20, avg: 20, total: 120 }, # Results in this
{loading: 30, avg: 25, total: 55 },
{loading: 10, avg: 20, total: 46 }
]
我试图修改此行
hash.each { |key, value| sum[key] += value }
添加一个条件,检查值是否重复,但我没有成功。
欢迎任何帮助,想法或任何事情。
答案 0 :(得分:4)
这似乎有效
array.group_by { |item| [item[:loading], item[:avg]] }.values.flat_map { |items| items.first.merge(total: items.sum { |h| h[:total] }) }
=> [{:loading=>10, :avg=>15, :total=>25}, {:loading=>20, :avg=>20, :total=>120}, {:loading=>30, :avg=>25, :total=>55}, {:loading=>10, :avg=>20, :total=>46}]
答案 1 :(得分:2)
您可以使用Enumerable#group_by
和Hash#merge!
来处理此问题
array.group_by {|h| [h[:loading],h[:avg]]}.values.map do |a|
a.inject do |memo,h|
memo.merge!(h) do |_k,old_value,new_value|
old_value + new_value
end
end
end
#=> [{:loading=>10, :avg=>15, :total=>25},
# {:loading=>40, :avg=>40, :total=>120},
# {:loading=>30, :avg=>25, :total=>55},
# {:loading=>10, :avg=>20, :total=>46}]
快速细分
array.group_by
按加载和平均值对元素进行分组,这将返回{grouped_values =>的哈希值[对象]} values
[个对象](因为我们并不特别关心密钥)map
成新数组inject
将第一个元素作为memo传递,并在第一次迭代时产生第二个元素。之后备忘录将是来自注入的返回值,并且下一个元素将被生成到块中,直到没有剩余元素为止。merge!
允许您处理重复的键。在这种情况下,您想要添加值。 答案 2 :(得分:1)
这使用Hash#update(aka merge!
)的形式,它使用一个块来确定合并的两个哈希中存在的键的值。 1 请参阅用于块变量_k
,o
和n
定义的doc。第一个变量(_k
)以下划线(通常只写_
)开头,表示该块变量未在块计算中使用。 (注意@engineersmnky dd相同。)
arr = [
{loading: 10, avg: 15, total: 25 },
{loading: 20, avg: 20, total: 40 },
{loading: 30, avg: 25, total: 55 },
{loading: 20, avg: 20, total: 80 },
{loading: 10, avg: 20, total: 46 }
]
arr.each_with_object({}) { |g,h| h.update(g.values_at(:loading, :avg)=>g) { |_k,o,n|
o.merge(total: o[:total]+n[:total]) } }.values
#=> [{:loading=>10, :avg=>15, :total=>25},
# {:loading=>20, :avg=>20, :total=>120},
# {:loading=>30, :avg=>25, :total=>55},
# {:loading=>10, :avg=>20, :total=>46}]
在最后应用.values
之前,我们将构建以下哈希:
arr.each_with_object({}) { |g,h| h.update(g.values_at(:loading, :avg)=>g) { |_k,o,n|
o.merge(total: o[:total]+n[:total]) } }
#=> {[10, 15]=>{:loading=>10, :avg=>15, :total=>25},
# [20, 20]=>{:loading=>20, :avg=>20, :total=>120},
# [30, 25]=>{:loading=>30, :avg=>25, :total=>55},
# [10, 20]=>{:loading=>10, :avg=>20, :total=>46}}
如果@Ursus(他的回答先于我的)采用了这种方法,我会使用group_by
。这两种方法似乎总是可以互换的。我不认为一个更好;这只是个人偏好的问题。似乎@engineersmnky无法下定决心,所以他使用了两者。
1。我觉得我已经写过这句话(逐字)数百次了。 ¯\ _(ツ)_ /¯