ruby-on-rails - 根据特定 ID 合并和求和哈希值,并保持剩余的哈希不变
问题描述
我尝试了多种方法,包括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
那些objects
具有相同pb_id
且具有opl_amount
key
. 如果他们没有opl_amount
key
,那么他们需要保持原样。这不应该那么难,但同样,我很难执行它。
解决方案
我的理解是,如果一组两个或多个哈希值相同,:pb_id
那么:
- 它们都有相同的键,包括一个键
:opl_amount
; - 以外的所有键的值
:opl_amount
都相等;和 - 它们将被替换为具有相同键和值的单个散列,除了 的值,该值
:opt_amount
将计算为:opl_amount
组中每个散列的值的总和(这需要在字符串和浮点数之间进行转换)。
一种方法是使用Hash#update (aka 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. 当块计算中不使用块变量时,通常的做法是通过使用前导下划线命名变量来向读者表明这一事实,通常仅使用下划线 ( |_,o,n|
)。