Ruby 带哈希的数组,如何合并相同的键并添加其值

Ruby 带哈希的数组,如何合并相同的键并添加其值,ruby,Ruby,我有一个包含散列的数组。如果它们有相同的键,我只想添加它的值 @receivers << result @receivers => [{:email=>"user_02@yorlook.com", :amount=>10.00}] result => {:email=>"user_02@yorlook.com", :amount=>7.00} 有人知道怎么做吗? 下面是整个方法的步骤 def receivers @receivers

我有一个包含散列的数组。如果它们有相同的键,我只想添加它的值

@receivers << result

@receivers
=> [{:email=>"user_02@yorlook.com", :amount=>10.00}]
result
=> {:email=>"user_02@yorlook.com", :amount=>7.00}
有人知道怎么做吗?

下面是整个方法的步骤

  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
def接收机
@接收者=[]
命令。每个人都命令|
product\u email=order.product.user.paypal\u email
装备\电子邮件=order.装备\用户.paypal\电子邮件
如果order.user_拥有_装备?
结果={电子邮件:产品\电子邮件,金额:金额(订单.总价)}
其他的
结果={电子邮件:产品\电子邮件,金额:金额(订单.总价,0.9),
电子邮件:装备电子邮件,金额:金额(订单.总价,0.1)}
结束

@接收者我会这样写代码:

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
使用

使用

#输出:[{”em@il.one" => 29.0 }, { "em@il.two" => 39.0 }]
def接收器
如果@receivers返回@receivers
#产生:{”em@il.one" => 29.0, "em@il.two" => 39.0 }
partial_result=orders.reduce Hash.new(0.00)do| result,order|
product\u email=order.product.user.paypal\u email
装备\电子邮件=order.装备\用户.paypal\电子邮件
如果order.user_拥有_装备?
结果[产品\电子邮件]+=金额(订单.总价)
其他的
结果[产品\电子邮件]+=金额(订单.总价,.9)
结果[装备电子邮件]+=金额(订单.总价,.1)
结束
结果
结束
@接收者=部分结果。减少[]do |结果(电子邮件,金额)|
结果量}
结束
结束

据我所知,你只需
就可以逃脱。注入

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
}

“同一个键”是指相同的<代码>:电子邮件< /代码>值?@斯特凡,这是一个很好的问题。循环的显式类型检查和<代码>不是非常习惯的。嗯,它不是在循环中,但是这个想法是,你可以提供不同的方式调用MeoDoice的纯粹风格,但是考虑<代码>返回NIL如果目的地。source=[source]如果source\u class==Hash
。(如果哈希===source,则为
)。您可以在[*源代码]
中为项编写
,而不必将
源代码
转换为数组。(这是我第一次为……写
:-))。
@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}]
@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}]
@receivers.each_with_object(Hash.new(0)) {|h, nh| nh[h[:email]]+= h[:amount] }.map do |k, v|
 {email: k, amount: v}
end
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
# 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
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
}