这里有两种方法。
arr = [[ '01-01-2001', 4 ], [ '01-01-2001', 5 ], [ '01-01-2001', 6 ], [ '01-02-2001', 7]]
使用Enumerable#group_by
arr.group_by(&:first).transform_values { |v| v.sum(&:last).fdiv(v.size) }
#=> {"01-01-2001"=>5.0, "01-02-2001"=>7.0}
请参阅Hash#transform_values、Array#sum 和 Numeric#fdiv。
第一步是按日期对元素进行分组:
arr.group_by(&:first)
#=> {"01-01-2001"=>[["01-01-2001", 4], ["01-01-2001", 5], ["01-01-2001", 6]],
# "01-02-2001"=>[["01-02-2001", 7]]}
使用Hash#update
这种方式使用Hash#update(又名merge!)的形式,它使用一个块来确定在被合并的两个散列中存在的键的值。
arr.each_with_object({}) do |(k,v), h|
h.update(k=>[v, 1]) { |_k, (otot, onbr), (ntot, nnbr)| [otot+ntot, onbr+1] }
end.transform_values { |tot, nbr| tot.fdiv(nbr) }
请参阅文档以了解块中使用的三个块变量的解释,这些变量返回包含在被合并的两个哈希中的每个键的值。对于每个不同的日期字符串,正在构造的哈希 h 包含一个 2 元素数组,其第一个值是给定日期的值的运行总和,第二个值是该日期的出现次数。只保留所有值的总和当然比维护所有值的数组更节省空间,就像group_by 方法所做的那样。
请注意,Ruby 允许 h.update(k=>[v, 1]) 作为 h.update({ k=>[v, 1] }) 的简写。