将散列组合在一起以连接键的值

Grouping hashes together to concat a key's values

我有一个哈希数组,如下所示:

records = [
    { id: "PU525", note: "Foo" },
    { id: "PU525", note: "Bar" },
    { id: "DT525", note: "Hello World" },
    { id: "PU680", note: "Fubar" }
]

最终结果应该是:

result = [
    { id: "PU525", note: "FooBar" },
    { id: "DT525", note: "Hello World" },
    { id: "PU680", note: "Fubar" }
]

我开始玩 Enumerable#group_by 的是:

results = records.group_by { |record| record[:id] }

# Results in:
# {
#     "PU525": [
#         { id: "PU525", note: "Foo" },
#         { id: "PU525", note: "Bar" }
#     ],
#     "DT525": { id: "DT525", note: "Hello World" },
#     "PU680": { id: "PU680", note: "Fubar" }
# }

下一步将是使用 inject 进一步减少数据,但我想知道是否有更简单的方法可以将原始数组减少到我正在寻找的结果而无需这么多步骤?

你快完成了:

records = [ 
    { id: "PU525", note: "Foo" },
    { id: "PU525", note: "Bar" },
    { id: "DT525", note: "Hello World" },
    { id: "PU680", note: "Fubar" }
]

arr = records.group_by { |record| record[:id] }
             .map do |k, v|
                [k, v.reduce('') { |memo, h| memo + h[:note] } ] 
             end
             .map do |a| 
                { id: a.first, note: a.last }
             end
#⇒ [
#     { id: "PU525", note: "FooBar" },
#     { id: "DT525", note: "Hello World" },
#     { id: "PU680", note: "Fubar" }
# ]

UPD 毕竟,你让我纠结于这种愚蠢的 group_by 方法。一切都变得更简单了。

records.inject({}) do |memo, el| 
  (memo[el[:id]] ||= '') << el[:note]
  memo
end.map { |k, v| { id: k, note: v } }

这是另一种方法,在使用 #group_by 之后:

records = [
    { id: "PU525", note: "Foo" },
    { id: "PU525", note: "Bar" },
    { id: "DT525", note: "Hello World" },
    { id: "PU680", note: "Fubar" }
]

hsh = records.group_by { |record| record[:id] }.map do |_, v|
  v.inject do |h1, h2|
    h1.update(h2) { |k, o, n| k == :note ? o << n : n }
  end
end

p hsh
# >> [{:id=>"PU525", :note=>"FooBar"}, {:id=>"DT525", :note=>"Hello World"}, {:id=>"PU680", :note=>"Fubar"}]

下面是上述的几个变体。

使用Enumerable#group_by

records.group_by { |h| h[:id] }.map { |id, arr|
  { id: id, note: arr.map { |h| h[:note] }.join } }
  #=> [{:id=>"PU525", :note=>"FooBar"},
  #    {:id=>"DT525", :note=>"Hello World"},
  #    {:id=>"PU680", :note=>"Fubar"}]

使用Hash#update(又名merge!

records.each_with_object({}) { |g,h| h.update(g[:id]=>g) { |_,og,ng|
  { id: g[:id], note: og[:note]+ng[:note] } } }.values
  #=>[{:id=>"PU525", :note=>"FooBar"},
  #   {:id=>"DT525", :note=>"Hello World"},
  #   {:id=>"PU680", :note=>"Fubar"}]