我试图从ruby散列中求值,但使用inject或reduce不会返回正确的答案。看起来这些方法似乎覆盖了存储的当前值而不是将它们相加。
我的哈希看起来像这样:
@test = [
{"total"=>18, "type"=>"buy", "date"=>Thu, 21 Nov 2013, "instrument_code"=>"food"},
{"total"=>92, "type"=>"buy", "date"=>Thu, 14 Nov 2013, "instrument_code"=>"food"},
{"total"=>12, "type"=>"buy", "date"=>Wed, 20 Nov 2013, "instrument_code"=>"drink"},
{"total"=>1, "type"=>"buy", "date"=>Mon, 11 Nov 2013, "instrument_code"=>"food"}
]
这是我的注入代码失败:
def additions_per_security
@test.group_by { |i| i.type }.each do |key, value|
if key == "buy"
value.group_by{ |i| i.date }.each do |key, value|
@sortable_additions[key] = value
end
@sorted_additions = @sortable_additions.sort_by { |key,value| key }
@sorted_additions.shift
@additions_per_security = Hash[@sorted_additions.map { |key, value|
[key, value]
}]
@additions_per_security.each do |key, value|
value.group_by { |i| i.instrument_code }.each do |key, value|
@additions_security[key] = value.inject(0){ |result, transaction|
(result += transaction.total)
}
end
end
end
end
return @additions_security
end
这是我的reduce代码失败:
def additions_per_security
@@test.group_by { |i| i.type }.each do |key, value|
if key == "buy"
value.group_by { |i| i.date }.each do |key, value|
@sortable_additions[key] = value
end
@sorted_additions = @sortable_additions.sort_by { |key,value| key }
@sorted_additions.shift
@additions_per_security = Hash[@sorted_additions.map { |key, value|
[key, value]
}]
@additions_per_security.each do |key, value|
value.group_by { |i| i.instrument_code }.each do |key, value|
@additions_security[key] = value.map { |p| p.total }.reduce(0,:+)
end
end
end
end
return @additions_security
end
我有一个哈希,我想总结所有键的总数,除了第一个日期。
我目前正在接受以下内容:
{"drink"=>12.0, "food"=>92}
我的预期结果如下:
{"drink"=>12.0, "food"=>110}
提前感谢任何建议。
答案 0 :(得分:26)
如果你有简单的键/值哈希
{1 => 42, 2 => 42}.values.sum
=> 84
答案 1 :(得分:7)
我对您的inject
代码提出以下意见:
@
)就足够了; test.group_by {|i| i.type}...
应为test.group_by {|i| i["type"]}...
@sortable_additions[key]=value
应该引发异常,因为尚未创建哈希值; @sorted_additions.shift
删除哈希的第一个元素并返回该元素,但没有变量可以接收它(例如,h = @sorted_additions.shift
); @additions_per_security = Hash[@sorted_additions.map { |key, value|[key, value]}]
似乎将@sorted_additions转换为数组,然后返回相同的哈希值。 以下是一种做你想做的事情的方法。
首先,您将传递日期对象。为了解决这个问题,我们首先为你的示例中的日期创建日期对象:
require 'date'
date1 = Date.parse("Thu, 21 Nov 2013") # => #<Date: 2013-11-21 ((2456618j,0s,0n),+0s,2299161j)>
date2 = Date.parse("Thu, 14 Nov 2013") # => #<Date: 2013-11-14 ((2456611j,0s,0n),+0s,2299161j)>
date3 = Date.parse("Thu, 20 Nov 2013") # => #<Date: 2013-11-20 ((2456617j,0s,0n),+0s,2299161j)>
date4 = Date.parse("Thu, 11 Nov 2013") # => #<Date: 2013-11-11 ((2456608j,0s,0n),+0s,2299161j)>
进行测试:
test = [{"total"=>18, "type"=>"buy", "date"=>date1, "instrument_code"=>"food"},
{"total"=>92, "type"=>"buy", "date"=>date2, "instrument_code"=>"food"},
{"total"=>12, "type"=>"buy", "date"=>date3, "instrument_code"=>"drink"},
{"total"=> 1, "type"=>"buy", "date"=>date4, "instrument_code"=>"food"}]
现在我们计算出我们需要的东西。
test_buy = test.select {|h| h["type"] == "buy"}
earliest = test_buy.min_by {|h| h["date"]}["date"]
# => #<Date: 2013-11-11 ((2456608j,0s,0n),+0s,2299161j)>
all_but_last = test.reject {|h| h["date"] == earliest}
# => [{"total"=>18, "type"=>"buy", "date"=>date1, "instrument_code"=>"food"},
{"total"=>92, "type"=>"buy", "date"=>date2, "instrument_code"=>"food"},
{"total"=>12, "type"=>"buy", "date"=>date3, "instrument_code"=>"drink"}]
或者我们可以使用Enumerable#select
:
all_but_last = test.select {|h| h["date"] != earliest}
请注意,此处和下方会显示date1
,date2
和date3
的值(例如,#<Date: 2013-11-21 ((2456618j,0s,0n),+0s,2299161j)>
会显示date1
) ;我在这里使用变量名作为占位符,以使其更具可读性。此外,所有带h
的哈希h["date"] = earliest
都将被拒绝(如果有多个哈希值)。
grouped = all_but_last.group_by {|h| h["instrument_code"]}
# => {"food" =>[{"total"=>18, "type"=>"buy", "date"=>date1, "instrument_code"=>"food"},
{"total"=>92, "type"=>"buy", "date"=>date2, "instrument_code"=>"food"}],
"drink"=>[{"total"=>12, "type"=>"buy", "date"=>date3, "instrument_code"=>"drink"}]}
keys = grouped.keys # => ["food", "drink"]
arr = keys.map {|k| [k, grouped[k].reduce(0) {|t,h| t + h["total"]}]}
# => [["food", 110], ["drink", 12]]
Hash[arr] # => {"food"=>110, "drink"=>12}
我使用了一些临时变量,包括test_buy
,earliest
,all_but_last
,grouped
,keys
和arr
。您可以通过“链接”来消除其中的一些。在这里,我将向您展示如何摆脱其中一些:
test_buy = test.select {|h| h["type"] == "buy"}
earliest = test_buy.min_by {|h| h["date"]}["date"]
grouped = test_buy.reject {|h| h["date"] == earliest}.group_by \
{|h| h["instrument_code"]}
Hash[grouped.keys.map {|k| [k, grouped[k].reduce(0) \
{|t,h| t + h["total"]}]}] # => {"food"=>110, "drink"=>12}
您可能认为这看起来很复杂,但在您获得Ruby经验后,它看起来非常自然且易于阅读。但是,使用链接的程度是样式首选项。
答案 2 :(得分:0)
尝试:
test = [
{"total"=>18, "type"=>"buy", "date"=>Thu, 21 Nov 2013, "instrument_code"=>"food"},
{"total"=>92, "type"=>"buy", "date"=>Thu, 14 Nov 2013, "instrument_code"=>"food"},
{"total"=>12, "type"=>"buy", "date"=>Wed, 20 Nov 2013, "instrument_code"=>"drink"},
{"total"=>1, "type"=>"buy", "date"=>Mon, 11 Nov 2013, "instrument_code"=>"food"}
]
except_first_date = test.sort_by {|i| i['date'] }
except_first_date.shift
result = except_first_date.inject({}) {|m,i| m[i["instrument_code"]] = m[i["instrument_code"]].to_f + i['total'] ; m }
# => {"food"=>110.0, "drink"=>12.0}