我有这些数据:
@complete_transactions = [{"timestamp"=>"2018-01-18T02:57:34.959Z", "toAddress"=>"Alice", "amount"=>"50"},
{"timestamp"=>"2018-01-18T02:57:35.016Z", "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"12.5"},
{"timestamp"=>"2018-01-18T16:53:16.747Z", "toAddress"=>"50", "amount"=>"50"},
{"timestamp"=>"2018-01-18T16:53:27.572Z", "fromAddress"=>"50", "toAddress"=>"alice", "amount"=>"50"},
{"timestamp"=>"2018-01-18T16:53:38.853Z", "fromAddress"=>"alice", "toAddress"=>"Alice", "amount"=>"50"},
{"timestamp"=>"2018-01-23T23:35:03.792Z", "fromAddress"=>"Alice", "toAddress"=>"alice", "amount"=>"10"},
{"timestamp"=>"2018-01-23T23:35:25.464Z", "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"1"},
{"timestamp"=>"2018-01-23T23:35:48.835Z", "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"1"},
{"timestamp"=>"2018-01-23T23:47:46.485Z", "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"1"},
{"timestamp"=>"2018-01-23T23:48:31.953Z", "fromAddress"=>"Alice", "toAddress"=>"Bobz", "amount"=>"1"},
{"timestamp"=>"2018-01-24T18:11:04.444Z", "fromAddress"=>"Alice", "toAddress"=>"Bobz", "amount"=>"1"},
{"timestamp"=>"2018-01-24T18:28:40.680Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"3"},
{"timestamp"=>"2018-01-24T18:36:53.179Z", "fromAddress"=>"Alice", "toAddress"=>"Sally", "amount"=>"3"},
{"timestamp"=>"2018-01-24T18:39:14.926Z", "fromAddress"=>"Alice", "toAddress"=>"Sally", "amount"=>"3"},
{"timestamp"=>"2018-01-24T18:39:40.937Z", "fromAddress"=>"Alice", "toAddress"=>"Sally", "amount"=>"3"},
{"timestamp"=>"2018-01-24T18:40:11.686Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T18:40:13.720Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T18:41:32.832Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T18:49:10.052Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T18:49:11.729Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T18:50:09.862Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T19:14:46.326Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T20:29:30.973Z", "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"3"},
{"timestamp"=>"2018-01-24T20:31:37.491Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T20:35:06.693Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T21:29:21.465Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-24T21:29:27.637Z", "fromAddress"=>"Alice", "toAddress"=>"bozb", "amount"=>"2"},
{"timestamp"=>"2018-01-26T19:04:56.197Z", "fromAddress"=>"Alice", "toAddress"=>"bob", "amount"=>"2"},
{"timestamp"=>"2018-01-28T19:53:12.502Z", "toAddress"=>"1444", "amount"=>"50"},
{"timestamp"=>"2018-01-28T19:53:21.318Z", "fromAddress"=>"1444", "toAddress"=>"0297bc77", "amount"=>"1"},
{"timestamp"=>"2018-01-28T19:53:30.947Z", "fromAddress"=>"1444", "toAddress"=>"0297bc77", "amount"=>"1"},
{"timestamp"=>"2018-01-28T19:54:11.119Z", "fromAddress"=>"1444", "toAddress"=>"0297bc77", "amount"=>"1"},
{"timestamp"=>"2018-01-28T21:26:58.551Z", "fromAddress"=>"1444", "toAddress"=>"Alice", "amount"=>"1"},
{"timestamp"=>"2018-01-28T21:28:13.499Z", "fromAddress"=>"1444", "toAddress"=>"Alice", "amount"=>"2"},
{"timestamp"=>"2018-01-28T21:31:47.454Z", "fromAddress"=>"1444", "toAddress"=>"something else", "amount"=>"2"},
{"timestamp"=>"2018-01-28T21:39:16.644Z", "fromAddress"=>"1444", "toAddress"=>"Alice", "amount"=>"3"},
{"timestamp"=>"2018-01-28T21:39:41.527Z", "fromAddress"=>"1444", "toAddress"=>"Alice", "amount"=>"2"},
我想要的是按toAddress
字段对数据进行分组,并总计金额。
我喜欢这样的事情(通知时间戳无关紧要):
[
{
'toAddress' => 'bob', amount: '20', fromAddress: ['Alice', '1444']
},
{
'toAddress' => 'Sally', amount: '9', fromAddress: ['Alice'],
},
...
]
有关如何执行此操作的任何建议吗?
这会产生一个我认为正确的数据......但感觉很糟糕:
complete_transactions.group_by {|trans| trans['toAddress']}.map do |group, transactions|
transactions.reduce do |h1, h2|
h1.merge(h2) do |key, old, new|
if key == 'amount'
old.to_i + new.to_i
elsif key == 'fromAddress'
[old, new].flatten.uniq
else
old
end
end
end
end
导致正确的结果,但感觉很糟糕。还有更好的方法吗?
这是一小部分数据样本和预期结果:
transactions
=> [{"timestamp"=>"2018-01-23T23:48:31.953Z", "fromAddress"=>"Alice", "toAddress"=>"Bobz", "amount"=>"1"}, {"timestamp"=>"2018-01-24T18:11:04.444Z", "fromAddress"=>"Alice", "toAddress"=>"Bobz", "amount"=>"1"}, {"timestamp"=>"2018-01-24T18:11:04.444Z", "fromAddress"=>"Another", "toAddress"=>"Bobz", "amount"=>"1"}]
transactions.reduce do |h1, h2|
irb(main):007:1* h1.merge(h2) do |key, old, new|
irb(main):008:2* if key == 'amount'
irb(main):009:3> old.to_i + new.to_i
irb(main):010:3> elsif key == 'fromAddress'
irb(main):011:3> [old, new].flatten.uniq
irb(main):012:3> else
irb(main):013:3* old
irb(main):014:3> end
irb(main):015:2> end
irb(main):016:1> end
=> {"timestamp"=>"2018-01-23T23:48:31.953Z", "fromAddress"=>["Alice", "Another"], "toAddress"=>"Bobz", "amount"=>3}
答案 0 :(得分:4)
我相信这就是你需要的。
result = @complete_transactions
.group_by{|hash| hash['toAddress']}
.map do |key, value|
{
'toAddress' => key,
'amount' => value.sum {|val| val['amount'].to_i},
'fromAddress' => value.map {|val| val['fromAddress']}.uniq
}
end
p result
这适用于2.4.0之后的Ruby版本。对于先前版本,请使用此计算金额总和。
'amount' => value.map {|val| val['amount'].to_i}.inject(:+)
以下语句按其' toAddress'对所有哈希值进行分组。值。
.group_by{|hash| hash['toAddress']}
followins语句遍历每个结果哈希并创建一个新哈希。
.map do |key, value|
在下面的块中,我们通过操作每个散列的值来创建所需的散列。
{
'toAddress' => key,
'amount' => value.sum {|val| val['amount'].to_i},
'fromAddress' => value.map {|val| val['fromAddress']}.uniq
}
对于2.4.0之前的Ruby版本,代码变为。
{
'toAddress' => key,
'amount' => value.map {|val| val['amount'].to_i}.inject(:+),
'fromAddress' => value.map {|val| val['fromAddress']}.uniq
}
希望这有帮助。
答案 1 :(得分:1)
我编写了一个提供您要求的方法但另外我提供了一些您没有要求的方法:每个“fromAddress”对每个“toAddress”的总“金额”的贡献。 (我误读了这个问题。¯\ _(ツ)_ /¯)
<强>代码强>
def doit(transactions)
transactions.each_with_object(Hash.new(0)) do |g,h|
a = [g["fromAddress"], g["toAddress"]]
h.update(a => h[a] += g["amount"].to_f)
end.
group_by { |(_from, to), _amt| to }.
map { |k,v| { toAddress: k, amount: v.map(&:last).sum.to_s,
from_address: v.map { |(from, _to), amt| [from, amt.to_s] }.to_h } }
end
示例强>
让我们将示例简化为更易于管理的内容。我已经删除了@transactions
的一些元素(哈希),并从每个哈希中删除了我已经删除了密钥"timestamp"
,因为它与问题无关。
transactions = [
{ "toAddress"=>"Alice", "amount"=>"50" },
{ "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"12.5" },
{ "toAddress"=>"50", "amount"=>"50" },
{ "fromAddress"=>"50", "toAddress"=>"Alice", "amount"=>"50" },
{ "fromAddress"=>"Alice", "toAddress"=>"Alice", "amount"=>"50" },
{ "fromAddress"=>"Alice", "toAddress"=>"Bob", "amount"=>"1" },
{ "fromAddress"=>"1444", "toAddress"=>"0297bc77", "amount"=>"1"},
{ "fromAddress"=>"1444", "toAddress"=>"0297bc77", "amount"=>"1"},
{ "fromAddress"=>"1444", "toAddress"=>"Alice", "amount"=>"1"},
{ "fromAddress"=>"1444", "toAddress"=>"Alice", "amount"=>"2"}
]
doit(transactions)
#=> [
# {:toAddress=>"Alice", :amount=>"153.0",
# :from_address=>{nil=>"50.0", "50"=>"50.0", "Alice"=>"50.0", "1444"=>3.0}},
# {:toAddress=>"Bob", :amount=>"13.5",
# :from_address=>{"Alice"=>"13.5"}},
# {:toAddress=>"50", :amount=>"50.0",
# :from_address=>{nil=>"50.0"}},
# {:toAddress=>"0297bc77", :amount=>"2.0",
# :from_address=>{"1444"=>"2.0"}}
# ]
如果您不希望返回值包含某些元素,则需要从transactions
中删除相应的哈希值作为第一步(例如transactions.reject { |h| .... }.each_with_object...
)。
<强>解释强>
步骤如下。
h = @transactions.each_with_object(Hash.new(0)) do |g,h|
a = [g["fromAddress"], g["toAddress"]]
h.update(a => h[a] += g["amount"].to_f)
end
#=> {[nil, "Alice"]=>50.0, ["Alice", "Bob"]=>13.5, [nil, "50"]=>50.0,
# ["50", "Alice"]=>50.0, ["Alice", "Alice"]=>50.0, ["1444", "0297bc77"]=>2.0,
# ["1444", "Alice"]=>3.0}
g = h.group_by { |(_from, to), _amt| to }
#=> { "Alice"=>[[[nil, "Alice"], 50.0], [["50", "Alice"], 50.0],
# [["Alice", "Alice"], 50.0], [["1444", "Alice"], 3.0]],
# "Bob"=>[[["Alice", "Bob"], 13.5]], "50"=>[[[nil, "50"], 50.0]],
# "0297bc77"=>[[["1444", "0297bc77"], 2.0]]}
g.map do |k,v|
{ toAddress: k, amount: v.map(&:last).sum.to_s,
from_address: v.map { |(from, _to), amt| [from, amt.to_s] }.to_h }
end
#=> <return value shown in example>