Ruby按金额选择前三组

时间:2016-06-29 14:38:07

标签: ruby

我有一个数组,我需要按名称对数组进行分组,然后总结每个组的总数,然后选择每组最高数量的前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)

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_bymin也是如此。