我有数组
arr = [
["BEER", 37],
["BEER", 95],
["BEER", 85],
["BEER", 60],
["BEER", 36],
["FOOD", 31],
["FOOD", 86],
["FOOD", 50],
["FOOD", 0]
]
如何获取类似的数组
new_arr = [ [ 'FOOD', sum_of_food ],
['BEER', sum_of_beer] ]
我刚刚通过Model.all.map {|c| [c.source, c.amount ] }
得到arr
您可以使用Enumerable#inject
循环集合中的每个项目,并将池计算到用作累加器的新数组中。
arr = [
["BEER", 37],
["BEER", 95],
["BEER", 85],
["BEER", 60],
["BEER", 36],
["FOOD", 31],
["FOOD", 86],
["FOOD", 50],
["FOOD", 0],
]
arr.inject({}) do |accumulator, (what, total)|
accumulator[what] ||= 0
accumulator[what] += total
accumulator
end
如果需要Array
而不是Hash,只需对结果调用to_a
即可。
如果数据存储在数据库中,则可以使用SQL SUM()
语句直接查询数据库。
results = Model.select('source, SUM(amount) AS total').group(:source)
result = results.first
result.source
# => FOO
result.total
# => the sum of amount for FOO
您可以使用三种可枚举方法:group_by
、map
和reduce
(也称为inject
):
arr.group_by(&:first).map { |k,v| [k, v.map(&:last).reduce(:+)] }
#=> [["BEER", 313],["FOOD", 167]]
步骤:
h = arr.group_by(&:first)
# => {"BEER"=>[["BEER", 37], ["BEER", 95], ["BEER", 85], ["BEER", 60],
# ["BEER", 36]],
# "FOOD"=>[["FOOD", 31], ["FOOD", 86], ["FOOD", 50], ["FOOD", 0]]}
map
将块变量分配给h
:的第一个1元素(键值对)
k = "BEER"
v = [["BEER", 37], ["BEER", 95], ["BEER", 85], ["BEER", 60], ["BEER", 36]]
然后执行块计算:
[k, v.map(&:last).reduce(:+)]
#=> ["BEER", [37, 95, 85, 60, 36].reduce(:+)]
# ["BEER", 313]
h
的第二个元素被传递到块:
k = "FOOD"
v = [["FOOD", 31], ["FOOD", 86], ["FOOD", 50], ["FOOD", 0]]
[k, v.map(&:last).reduce(:+)]
#=> ["FOOD", [31, 86, 50, 0].reduce(:+)]
# ["FOOD", 167]
如果已知arr
的对由对的第一个元素分组,如示例中所示,我们可以使用Enumerable#chunk:
arr.chunk(&:first).map { |k,v| [k, v.map(&:last).reduce(:+)] }
1由于Ruby v1.9哈希密钥是按插入顺序排列的。因此,可以引用散列的第n个元素(键值对)。在v1.9之前,没有哈希密钥排序的概念。对于这些版本,上面的代码运行良好,但我们不知道map
传递到其块的键值对的顺序