我是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
也许你可以给我或解释如何以红宝石的方式实现更好,更漂亮的方法?
答案 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