[英]Ruby Array of hashes: Better way to update deeply hash
我有一個由以下形式的哈希組成的數組:
array = [
{"id": 1, "items": [{"item_code": 1, "qty": 2},{"item_code": 2, "qty": 2}]},
{"id": 2, "items": [{"item_code": 3, "qty": 2},{"item_code": 4, "qty": 2}]},
{"id": 1, "items": [{"item_code": 5, "qty": 2},{"item_code": 6, "qty": 2}]},
{"id": 2, "items": [{"item_code": 7, "qty": 2},{"item_code": 8, "qty": 2}]}
]
我們是否有任何方便的方法根據ID合並項目:
預期產量:
array = [
{"id": 1, "items": [
{"item_code": 1, "qty": 2},
{"item_code": 2, "qty": 2},
{"item_code": 5, "qty": 2},
{"item_code": 6, "qty": 2}
]
},
{"id": 2, "items": [
{"item_code": 3, "qty": 2},
{"item_code": 4, "qty": 2},
{"item_code": 7, "qty": 2},
{"item_code": 8, "qty": 2}
]
}
]
我嘗試了不符合輸出格式的group_by。
ary.group_by { |elem| elem[:id] }.
each_with_object([]) do |(id, grouped_ary), out|
out << { id: id, items: grouped_ary.map { |h| h[:items] }.reduce(:|) }
end
=> [{:id=>1, :items=>[{:item_code=>1, :qty=>2},
{:item_code=>2, :qty=>2},
{:item_code=>5, :qty=>2},
{:item_code=>6, :qty=>2}]},
{:id=>2, :items=>[{:item_code=>3, :qty=>2},
{:item_code=>4, :qty=>2},
{:item_code=>7, :qty=>2},
{:item_code=>8, :qty=>2}]}]
不需要group_by
。 從頭開始直接使用each_with_object
。
array.
each_with_object({}) do |hash, acc|
acc[hash[:id]] ?
acc[hash[:id]][:items] |= hash[:items] :
acc[hash[:id]] = hash
end.values
#⇒ [{:id=>1, :items=>[{:item_code=>1, :qty=>2},
# {:item_code=>2, :qty=>2},
# {:item_code=>5, :qty=>2},
# {:item_code=>6, :qty=>2}]},
# {:id=>2, :items=>[{:item_code=>3, :qty=>2},
# {:item_code=>4, :qty=>2},
# {:item_code=>7, :qty=>2},
# {:item_code=>8, :qty=>2}]}]
您可以結合使用group_by
和transform_values!
(對於后者,你需要的Ruby 2.4.0或更高版本,否則,你可以使用each_with_object
作為@Jagdeep指出)
array.group_by { |item| item[:id] }
.transform_values! { |v| v.flat_map { |subitem| subitem[:items] } }
.map { |(id, items)| Hash["id", id, "items", items] }
首先,我映射ID,然后為每個ID用兩個鍵進行哈希處理:ID和每個條目項的展平圖:
result = array.group_by { |e| e[:id] }.map { |id, entries| {id: id, items: entries.flat_map { |entry| entry[:items] }} }
array.each_with_object({}) { |g,h| h.update(g[:id]=>g[:items]) { |_,o,n| o+n } }.
map { |k,v| { id: k, items: v } }
#=> [{:id=>1, :items=>[{:item_code=>1, :qty=>2}, {:item_code=>2, :qty=>2},
# {:item_code=>5, :qty=>2}, {:item_code=>6, :qty=>2}]},
# {:id=>2, :items=>[{:item_code=>3, :qty=>2}, {:item_code=>4, :qty=>2},
# {:item_code=>7, :qty=>2}, {:item_code=>8, :qty=>2}]}]
第一步是:
array.each_with_object({}) { |g,h| h.update(g[:id]=>g[:items]) { |_,o,n| o+n } }
#=> {1=>[{:item_code=>1, :qty=>2}, {:item_code=>2, :qty=>2},
# {:item_code=>5, :qty=>2}, {:item_code=>6, :qty=>2}],
# 2=>[{:item_code=>3, :qty=>2}, {:item_code=>4, :qty=>2},
# {:item_code=>7, :qty=>2}, {:item_code=>8, :qty=>2}]}
這利用了Hash#update的形式(又名merge!
),該形式采用一個塊來確定要合並的兩個哈希中存在的鍵的值。 有關三個塊變量的定義,請參見文檔。
或者,可以編寫以下內容。
array.each_with_object({}) { |g,h| h.update(g[:id]=>g) { |_,o,n|
o.merge(n) { |k,oo,nn| k == :items ? oo+nn : oo } } }.values
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.