I have an array with hashes in it. If they have the same key I just want to add its value.
我有一个包含哈希的数组。如果它们有相同的键,我只想添加它的值。
@receivers << result
@receivers
=> [{:email=>"user_02@yorlook.com", :amount=>10.00}]
result
=> {:email=>"user_02@yorlook.com", :amount=>7.00}
I want the result of above to look like this
我希望上面的结果是这样的
[{:email=>"user_02@yorlook.com", :amount=>17.00}]
Does anyone know how to do this?
有人知道怎么做吗?
Here is the the entire method
这是整个方法
def receivers
@receivers = []
orders.each do |order|
product_email = order.product.user.paypal_email
outfit_email = order.outfit_user.paypal_email
if order.user_owns_outfit?
result = { email: product_email, amount: amount(order.total_price) }
else
result = { email: product_email, amount: amount(order.total_price, 0.9),
email: outfit_email, amount: amount(order.total_price, 0.1) }
end
@receivers << result
end
end
5 个解决方案
#1
4
Using Enumerable#group_by
使用# group_by可列举的
@receivers.group_by {|h| h[:email]}.map do |k, v|
{email: k, amount: v.inject(0){|s,h| s + h[:amount] } }
end
# => [{:email=>"user_02@yorlook.com", :amount=>17.0}]
Using Enumerable#each_with_object
使用# each_with_object可列举的
@receivers.each_with_object(Hash.new(0)) {|h, nh| nh[h[:email]]+= h[:amount] }.map do |k, v|
{email: k, amount: v}
end
#2
1
# Output: [{ "em@il.one" => 29.0 }, { "em@il.two" => 39.0 }]
def receivers
return @receivers if @receivers
# Produces: { "em@il.one" => 29.0, "em@il.two" => 39.0 }
partial_result = orders.reduce Hash.new(0.00) do |result, order|
product_email = order.product.user.paypal_email
outfit_email = order.outfit_user.paypal_email
if order.user_owns_outfit?
result[product_email] += amount(order.total_price)
else
result[product_email] += amount(order.total_price, .9)
result[outfit_email] += amount(order.total_price, .1)
end
result
end
@receivers = partial_result.reduce [] do |result, (email, amount)|
result << { email => amount }
end
end
#3
0
I would just write the code this way:
我这样写代码:
def add(destination, source)
if destination.nil?
return nil
end
if source.class == Hash
source = [source]
end
for item in source
target = destination.find {|d| d[:email] == item[:email]}
if target.nil?
destination << item
else
target[:amount] += item[:amount]
end
end
destination
end
usage:
用法:
@receivers = []
add(@receivers, {:email=>"user_02@yorlook.com", :amount=>10.00})
=> [{:email=>"user_02@yorlook.com", :amount=>10.0}]
add(@receivers, @receivers)
=> [{:email=>"user_02@yorlook.com", :amount=>20.0}]
#4
0
a = [
{:email=>"user_02@yorlook.com", :amount=>10.0},
{:email=>"user_02@yorlook.com", :amount=>7.0}
]
a.group_by { |v| v.delete :email } # group by emails
.map { |k, v| [k, v.inject(0) { |memo, a| memo + a[:amount] } ] } # sum amounts
.map { |e| %i|email amount|.zip e } # zip to keys
.map &:to_h # convert nested arrays to hashes
#5
0
From what I understand, you could get away with just .inject
:
据我所知,你只要注射就行了。
a = [{:email=>"user_02@yorlook.com", :amount=>10.00}]
b = {:email=>"user_02@yorlook.com", :amount=>7.00}
c = {email: 'user_03@yorlook.com', amount: 10}
[a, b, c].flatten.inject({}) do |a, e|
a[e[:email]] ||= 0
a[e[:email]] += e[:amount]
a
end
=> {
"user_02@yorlook.com" => 17.0,
"user_03@yorlook.com" => 10
}
#1
4
Using Enumerable#group_by
使用# group_by可列举的
@receivers.group_by {|h| h[:email]}.map do |k, v|
{email: k, amount: v.inject(0){|s,h| s + h[:amount] } }
end
# => [{:email=>"user_02@yorlook.com", :amount=>17.0}]
Using Enumerable#each_with_object
使用# each_with_object可列举的
@receivers.each_with_object(Hash.new(0)) {|h, nh| nh[h[:email]]+= h[:amount] }.map do |k, v|
{email: k, amount: v}
end
#2
1
# Output: [{ "em@il.one" => 29.0 }, { "em@il.two" => 39.0 }]
def receivers
return @receivers if @receivers
# Produces: { "em@il.one" => 29.0, "em@il.two" => 39.0 }
partial_result = orders.reduce Hash.new(0.00) do |result, order|
product_email = order.product.user.paypal_email
outfit_email = order.outfit_user.paypal_email
if order.user_owns_outfit?
result[product_email] += amount(order.total_price)
else
result[product_email] += amount(order.total_price, .9)
result[outfit_email] += amount(order.total_price, .1)
end
result
end
@receivers = partial_result.reduce [] do |result, (email, amount)|
result << { email => amount }
end
end
#3
0
I would just write the code this way:
我这样写代码:
def add(destination, source)
if destination.nil?
return nil
end
if source.class == Hash
source = [source]
end
for item in source
target = destination.find {|d| d[:email] == item[:email]}
if target.nil?
destination << item
else
target[:amount] += item[:amount]
end
end
destination
end
usage:
用法:
@receivers = []
add(@receivers, {:email=>"user_02@yorlook.com", :amount=>10.00})
=> [{:email=>"user_02@yorlook.com", :amount=>10.0}]
add(@receivers, @receivers)
=> [{:email=>"user_02@yorlook.com", :amount=>20.0}]
#4
0
a = [
{:email=>"user_02@yorlook.com", :amount=>10.0},
{:email=>"user_02@yorlook.com", :amount=>7.0}
]
a.group_by { |v| v.delete :email } # group by emails
.map { |k, v| [k, v.inject(0) { |memo, a| memo + a[:amount] } ] } # sum amounts
.map { |e| %i|email amount|.zip e } # zip to keys
.map &:to_h # convert nested arrays to hashes
#5
0
From what I understand, you could get away with just .inject
:
据我所知,你只要注射就行了。
a = [{:email=>"user_02@yorlook.com", :amount=>10.00}]
b = {:email=>"user_02@yorlook.com", :amount=>7.00}
c = {email: 'user_03@yorlook.com', amount: 10}
[a, b, c].flatten.inject({}) do |a, e|
a[e[:email]] ||= 0
a[e[:email]] += e[:amount]
a
end
=> {
"user_02@yorlook.com" => 17.0,
"user_03@yorlook.com" => 10
}