我有数组数组
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] ]
我刚刚arr
Model.all.map {|c| [c.source, c.amount ] }
答案 0 :(得分:3)
您可以使用Enumerable#inject
循环集合中的每个项目,并将sump计算为一个用作累加器的新数组。
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
而不是哈希,只需在结果上调用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
答案 1 :(得分:1)
您可以使用三种Enumerable方法: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
传递给其块的键值对的顺序。