从哈希数组中构建哈希

时间:2013-08-14 18:15:37

标签: ruby

我是Ruby的新手并试图解决问题。我有一系列哈希:

list = [{"amount"=>2.25,"rel_id"=>1103, "date"=>"2012-12-21"},
 {"amount"=>2.75,"rel_id"=>1103, "date"=>"2012-12-24"},
 {"amount"=>2.85,"rel_id"=>666, "date"=>"2012-12-27"},
 {"amount"=>3.15,"rel_id"=>666, "date"=>"2012-12-28"}
 #and many many more..
]

我需要通过rel_id对它们进行分组,我可以看到它们的总量和日期,这种格式:

{1103=>{:total_amount=>5.0, :dates=>["2012-12-21", "2012-12-24"]}, 666=>{:total_amount=>6.0, :dates=>["2012-12-27", "2012-12-28"]}}

我用这种方式解决了这个问题,但我很确定这是做到这一点的最差方法之一,我认为这不是一种红宝石方式......

results = {}

list.each do |line|
 if !(results.has_key?(line["rel_id"]))
 results[line["rel_id"]]={:total_amount=>line["amount"],:dates=>[line["date"]]}
 else
 results[line["rel_id"]][:total_amount] = results[line["rel_id"]][:total_amount]+line["amount"]
 results[line["rel_id"]][:dates]<<line["date"]
 end
end

也许你可以给我或解释如何以红宝石的方式实现更好,更漂亮的方法?

4 个答案:

答案 0 :(得分:5)

您可以这样做:

list.each_with_object({}) do |details, rollup|
  rollup[details["rel_id"]] ||= { total_amount: 0, dates: [] }
  rollup[details["rel_id"]][:total_amount] += details["amount"]
  rollup[details["rel_id"]][:dates] << details["date"]
end

为可读性/名称而编辑。

答案 1 :(得分:1)

功能方法(我将使用mash,如果没有Facets则使用Hash[...]

purchases_grouped = list.group_by { |p| p["rel_id"] }
result = purchases_grouped.mash do |rel_id, purchases|
  total_amount = purchases.map { |p| p["amount"] }.reduce(:+)
  dates = purchases.map { |p| p["date"] }
  accumulated = {total_amount: total_amount, dates: dates}
  [rel_id, accumulated]
end
#=> {1103=>{:total_amount=>5.0, :dates=>["2012-12-21", "2012-12-24"]}, 
#    666 =>{:total_amount=>6.0, :dates=>["2012-12-27", "2012-12-28"]}}

答案 2 :(得分:1)

h = list.group_by{|h| h["rel_id"]}
h.each{|k, v| h[k] = {
  total_amount: v.inject(0){|x, h| x + h["amount"]},
  dates: v.map{|h| h["date"]},
}}

h # => ...

或者

h = list.group_by{|h| h["rel_id"]}
h.each{|k, v| h[k] = {
  total_amount: v.map{|h| h["amount"]}.inject(:+),
  dates: v.map{|h| h["date"]},
}}

h # => ...

答案 3 :(得分:0)

list = [
 {amount: 2.25, rel_id: 1103, date: "2012-12-21"},
 {amount: 2.75, rel_id: 1103, date: "2012-12-24"},
 {amount: 2.85, rel_id: 666, date: "2012-12-27"},
 {amount: 3.15, rel_id: 666, date: "2012-12-28"},
]

results = Hash.new do |hash, key| 
  hash[key] = {}
end

list.each do |hash|
  totals = results[hash[:rel_id]]

  totals[:amount] ||= 0
  totals[:amount] += hash[:amount]

  totals[:dates] ||= []
  totals[:dates] << hash[:date]
end

p results

--output:--
{1103=>{:amount=>5.0, :dates=>["2012-12-21", "2012-12-24"]}, 
 666=>{:amount=>6.0, :dates=>["2012-12-27", "2012-12-28"]}}

Alex Peachey修改了each_with_object解决方案:

results =  list.each_with_object({}) do |h, acc|
  record = acc[h["rel_id"]] 
  record ||= { total_amount: 0, dates: [] }
  record[:total_amount] += h["amount"]
  record[:dates] << h["date"]
end