根据特定 ID 合并和求和哈希值,并保持剩余哈希值不变
Merge and sum hash values based off of specific ID and keep remaining hash untouched
我尝试了多种方法,包括 group_by
和 sum
但是因为我的数组中有两个不同的结构化哈希,所以我很难解决它。
这是我的数据结构:
{
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_id
和 opl_amount
key
的 objects
。如果他们没有 opl_amount
key
,那么他们需要保持原样。这不应该那么难,但我还是很难执行它。
你的数据接缝是一个 Ruby 散列,但其中有一些错误(null
,DRIVER 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
我还没有测试过,但我认为这应该可行。
- 按
pb_id
对对象进行分组
- 遍历
pb_id
组。使用 partition
将它们分成两组:具有 opl_amount
的那些和没有 的那些
- 合并具有
opl_amount
. 的对象
- 创建包含此合并对象和未合并对象的列表。
- 展平,使所有
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|
)。
我尝试了多种方法,包括 group_by
和 sum
但是因为我的数组中有两个不同的结构化哈希,所以我很难解决它。
这是我的数据结构:
{
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_id
和 opl_amount
key
的 objects
。如果他们没有 opl_amount
key
,那么他们需要保持原样。这不应该那么难,但我还是很难执行它。
你的数据接缝是一个 Ruby 散列,但其中有一些错误(null
,DRIVER 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
我还没有测试过,但我认为这应该可行。
- 按
pb_id
对对象进行分组
- 遍历
pb_id
组。使用partition
将它们分成两组:具有opl_amount
的那些和没有 的那些
- 合并具有
opl_amount
. 的对象
- 创建包含此合并对象和未合并对象的列表。
- 展平,使所有
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
是公钥1o
是“旧”散列,这里是正在构建的散列,由块变量h
保存
n
是“新”散列,这里是{ g[:pb_id]=>g }
(可选地表示g[:pb_id]=>g
当方法的参数时)
请注意,解析块 未 在以下时间调用:
- 具有唯一值
:pb_id
的散列被合并到h
(包括那些没有键:opt_amount
)和 - 一组具有相同值
:pb_id
的散列的第一个散列被合并到h
.
1.当在块计算中不使用块变量时,通常的做法是通过使用前导下划线命名变量来向 reader 表明该事实,通常仅使用下划线 (|_,o,n|
)。