簡體   English   中英

Ruby哈希數組:更好地更新哈希的更好方法

[英]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。

使用group_byeach_with_object

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_bytransform_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM