根据特定 ID 合并和求和哈希值,并保持剩余哈希值不变

Merge and sum hash values based off of specific ID and keep remaining hash untouched

我尝试了多种方法,包括 group_bysum 但是因为我的数组中有两个不同的结构化哈希,所以我很难解决它。

这是我的数据结构:

{
DRIVER NAME: [
{
pb_id: "133599.0",
pbbname: "Company 1,
opl_amount: "101.0",
ops_type: "P",
ops_stop_id: 269802,
ops_order_id: 133599,
ops_driver1: 11,
ops_delivered_time: null
},
{
pb_id: "133599.0",
pbbname: "Company 1",
opl_amount: "11.62",
ops_type: "P",
ops_stop_id: 269802,
ops_order_id: 133599,
ops_driver1: 11,
ops_delivered_time: null
},
{
pb_id: "133699.0",
pbbname: "Company 1",
opl_amount: "66.0",
ops_type: "P",
ops_stop_id: 270022,
ops_order_id: 133699,
ops_driver1: 11,
ops_delivered_time: null
},
{
pb_id: "133501.0",
pbbname: "Company 2",
pb_net_rev: "675.0",
ops_driver1: 11,
ops_stop_id: 269587,
dh_first_name: "FIRST NAME",
dh_last_name: "SECOND",
ops_delivered_time: "2021-04-05T13:36:00.000-05:00"
},
]
}

我只想 merge 具有相同 pb_idopl_amount keyobjects。如果他们没有 opl_amount key,那么他们需要保持原样。这不应该那么难,但我还是很难执行它。

你的数据接缝是一个 Ruby 散列,但其中有一些错误(nullDRIVER NAME),所以我会像这样简化它:

data = [
  { pb_id: "133599.0", opl_amount: "101.0" },
  { pb_id: "133599.0", opl_amount: "11.62" },
  { pb_id: "133699.0", opl_amount: "66.0" },
  { pb_id: "133501.0" },
]

这是对您的 pb 的破坏性 merge! 函数:

def merge! data
  # group (by pb_id) the pbs (their index) that have opl_amount
  g = data.each_with_object({}).with_index do |(h,o),i|
    if h[:opl_amount]
      id = h[:pb_id]
      o[id] = [] unless o[id]
      o[id] << i
    end
  end
  # sum opl_amounts into the first pb of each group and annihilate the other pbs
  g.values.each do |a|
    next if a.count < 2
    first, *rest = a
    data[first][:opl_amount] = a.sum{|i| data[i][:opl_amount].to_f}.to_s
    rest.each { |i| data[i] = nil }
  end
  # delete the `nil` pbs
  data.compact!
end

你可以这样使用它:

merge! data
data.inspect
[{:pb_id=>"133599.0", :opl_amount=>"112.62"}, {:pb_id=>"133699.0", :opl_amount=>"66.0"}, {:pb_id=>"133501.0"}]

I ONLY want to merge the objects that have the same pb_id and that have a opl_amount key

result = {}

hash.each do |driver_name, objects|
  grouped_by_id = objects.group_by { |obj| obj["pb_id"] }.values

  new_objects = grouped_by_id.map do |group|
    has_amt, has_no_amt = group.partition { |obj| obj["opl_amount"] }
    has_amt.reduce(&:merge) + has_no_amt
  end.flatten

  result[driver_name] = new_objects
end

我还没有测试过,但我认为这应该可行。

  1. pb_id
  2. 对对象进行分组
  3. 遍历 pb_id 组。使用 partition 将它们分成两组:具有 opl_amount 的那些和没有
  4. 的那些
  5. 合并具有 opl_amount.
  6. 的对象
  7. 创建包含此合并对象和未合并对象的列表。
  8. 展平,使所有 pb_id 组成为一个列表

我的理解是,如果一组两个或多个哈希具有相同的值 :pb_id 那么:

  • 它们都有相同的密钥,包括一个密钥 :opl_amount;
  • :opl_amount以外的所有键的值都相等;和
  • 它们将被具有相同键和值的单个散列替换,:opt_amount 的值除外,该值将计算为 :opl_amount 的值的总和组中的每个散列(这需要在字符串和浮点数之间进行转换)。

这样做的一种方法是使用 Hash#update (a.k.a. merge!) 的形式,它使用一个块来确定存在于两个哈希中的键的值被合并。那些被合并的散列将有一个键,即 :pb_id.

假设给定的哈希数组如下。

arr = [
  { pb_id: "133599.0", pbbname: "Company 1", opl_amount: "101.0" },
  { pb_id: "133599.0", pbbname: "Company 1", opl_amount: "11.62" },
  { pb_id: "133699.0", pbbname: "Company 1", opl_amount: "66.0" },
  { pb_id: "133501.0", pbbname: "Company 2" }
]

然后我们可以进行以下计算。

arr.each_with_object({}) do |g,h|
  h.update(g[:pb_id]=>g) do |_k,o,n|
    o.merge(opl_amount: (o[:opl_amount].to_f + n[:opl_amount].to_f).to_s)
  end
end.values
  #=> [
  #    {:pb_id=>"133599.0", :pbbname=>"Company 1", :opl_amount=>"112.62"},
  #    {:pb_id=>"133699.0", :pbbname=>"Company 1", :opl_amount=>"66.0"},
  #    {:pb_id=>"133501.0", :pbbname=>"Company 2"}
  #   ]

发现Hash#values的接收者是:

{"133599.0"=>{:pb_id=>"133599.0", :pbbname=>"Company 1", :opl_amount=>"112.62"},
 "133699.0"=>{:pb_id=>"133699.0", :pbbname=>"Company 1", :opl_amount=>"66.0"},
 "133501.0"=>{:pb_id=>"133501.0", :pbbname=>"Company 2"}}

确定合并的两个散列中存在的键值的块是:

do |_k,o,n|
  o.merge(opl_amount: (o[:opl_amount].to_f + n[:opl_amount].to_f).to_s)
end

update

的文档中所述
  • _k是公钥1
  • o 是“旧”散列,这里是正在构建的散列,由块变量 h
  • 保存
  • n 是“新”散列,这里是 { g[:pb_id]=>g } (可选地表示 g[:pb_id]=>g 当方法的参数时)

请注意,解析块 在以下时间调用:

  • 具有唯一值:pb_id的散列被合并到h(包括那些没有键:opt_amount)和
  • 一组具有相同值:pb_id的散列的第一个散列被合并到h.

1.当在块计算中不使用块变量时,通常的做法是通过使用前导下划线命名变量来向 reader 表明该事实,通常仅使用下划线 (|_,o,n|)。