Ruby 如何对哈希数组进行分组和筛选。红宝石
我有以下数据:Ruby 如何对哈希数组进行分组和筛选。红宝石,ruby,Ruby,我有以下数据: @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"}, {"times
@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
字段对数据进行分组,并合计金额
我想要这样的东西(注意时间戳是不相关的):
有什么建议吗
我认为这会产生正确的数据。。。但感觉很恶心:
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}
我相信这就是你在这里需要的
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
}
希望这能有所帮助。我相信这正是您在这里需要的
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
}
希望这能有所帮助。我写了一个方法,提供了您想要的内容,但除此之外,我还包括了一些您没有要求的内容:每个“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
示例
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.reject{| h | |…}。每个_带有_对象…
)
解释
步骤如下
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>
h=@transactions.each_with_object(Hash.new(0))do|g,h|
a=[g[“fromAddress”],g[“toAddress”]]
h、 更新(a=>h[a]+=g[“金额”].\u f)
结束
#=>{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.群由{124;({U from,to),{U amt}to}
#=>{“爱丽丝”=>[[nil,“爱丽丝”],50.0],[50”,“爱丽丝”],50.0],
#[Alice”,“Alice”],50.0],[1444”,“Alice”],3.0],
#“Bob”=>[[[“Alice”,“Bob”],13.5],“50”=>[[[nil,”50“],50.0],
#“0297bc77”=>2.0]}
g、 图do | k,v|
{toAddress:k,amount:v.map(&:last).sum.to_s,
from|u地址:v.map{|(from,| to),amt |[from,amt.to|s]}to|h}
结束
#=>
我写了一个方法,提供了你想要的东西,但除此之外,我还包括了一些你没有要求的东西:每个“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
示例
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.reject{| h | |…}。每个_带有_对象…
)
解释
步骤如下
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>
h=@transactions.each_with_object(Hash.new(0))do|g,h|
a=[g[“fromAddress”],g[“toAddress”]]
h、 更新(a=>h[a]+=g[“金额”].\u f)
结束
#=>{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.群由{124;({U from,to),{U amt}to}
#=>{“爱丽丝”=>[[nil,“爱丽丝”],50.0],[50”,“爱丽丝”],50.0],
#[Alice”,“Alice”],50.0],[1444”,“Alice”],3.0],
#“Bob”=>[[[“Alice”,“Bob”],13.5],“50”=>[[[nil,”50“],50.0],
#“0297bc77”=>2.0]}
g、 图do | k,v|
{toAddress:k,amount:v.map(&:last).sum.to_s,
from|u地址:v.map{|(from,| to),amt |[from,amt.to|s]}to|h}
结束
#=>
sum
可以使用块,不需要在那里映射。@StefanPochmann谢谢你的建议。我已经做了更改。@SimpleTime是的,这可能会有帮助。而且,通过{散列|散列['toAddress']将U分组。大写}
可能更合适。但不确定OP想要什么。获取#的未定义方法
sum:“@Jwan622这一定是因为您使用的是2.4.0之前的Ruby版本。我也更新了答案以支持这一点。sum
可以使用块,不需要映射。@StefanPochmann感谢您的建议ion。我已经做了更改。@SimpleTime是的,这可能会有帮助。而且,group_by{hash}hash['toAddress']大写]
可能更合适。但不确定OP想要什么。获取#的未定义方法
sum:“@Jwan622这一定是因为您使用的是Ruby 2.4.0之前的版本。我也更新了答案以支持这一点。您的标题是filter,但我在您的问题中没有看到任何关于筛选的内容?您的标题是filter,但我没有看到我看不到关于filteri的任何信息