我有一个数组,我需要按名称对数组进行分组,然后总结每个组的总数,然后选择每组最高数量的前3个。
这是我的示例数组
@transactions =
[{"amount"=>-3000, "name"=>"CAR"},
{"amount"=>-600, "name"=>"BOAT"},
{"amount"=>-600, "name"=>"BOAT"},
{"amount"=>-600, "name"=>"BOAT"},
{"amount"=>-125, "name"=>"HOUSE" },
{"amount"=>-125, "name"=>"HOUSE" },
{"amount"=>-125, "name"=>"HOUSE" },
{"amount"=>-125, "name"=>"HOUSE" },
{"amount"=>-6000, "name"=>"PLANE" }]
回应应该是:
[PLANE, CAR, BOAT]
我目前有这个,但它不起作用:
transactions.group_by { |trans| trans.fetch('name') }.map do |amount, transactions|
[amount, transactions.map { |t| t[:amount] }.sum.abs.round(2)].select(3)
答案 0 :(得分:2)
您可以构建类型(名称)的哈希值,并在执行时对值进行求和:
@transactions.each_with_object(Hash.new(0)) do |obj, hash|
hash[obj["name"]] += obj["amount"].abs
end
然后你可以添加一些moar魔法,或者将其分解成更多行(建议可读性):
@transactions.each_with_object(Hash.new(0)) do |obj, hash|
hash[obj["name"]] += obj["amount"].abs
end.sort_by(&:last).map(&:first).last(3).reverse
基本上,这是按值排序(将新哈希转换为元组数组),然后映射每个元组的第一个值(名称),然后取前3个。
我没有注意到负面因素,所以我在获取金额的绝对值时进行求和,然后sort_by从最小到最大排序,所以取 last 三并反转给你最大到最小的顺序。
在这样的小块中有点复杂,我建议将其分解。
答案 1 :(得分:0)
假设每个组中的金额总是相同的(大假设):
@transactions.group_by { |t| t["name"] }.
sort_by { |_, v| v.first.first.last.abs }.
take(3).
map(&:first)
=> ["HOUSE", "BOAT", "CAR"]
答案 2 :(得分:0)
def doit(trans, top_nbr)
trans.each_with_object(Hash.new(0)) { |g,h| h[g["name"]] += g["amount"] }.
min_by(top_nbr, &:last).map(&:first)
end
doit(@transactions, 3)
#=> ["PLANE", "CAR", "BOAT"]
doit(@transactions, 99)
#=> ["PLANE", "CAR", "BOAT", "HOUSE"]
由于只返回几个键,如果哈希数组很大,使用Enumerable#min_by比对整个数组进行排序更快。允许min_by
在Ruby v2.2中有一个可选参数。 (Enumerable
的{{1}},max_by
和min
也是如此。