将哈希分组在一起以连接键的值

时间:2021-11-23 18:09:42

I have an array of hashes like the following:

我有一系列哈希,如下所示:

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

The end result should be:

最终结果应该是:

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

I started playing a little bit with Enumerable#group_by with the following:

我开始使用以下内容与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" }
# }

The next step would be to use inject to reduce the data down further, but I'm wondering if there's an easier way to reduce down the original array to what I'm looking for as a result without so many steps?

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

3 个解决方案

#1


You are nearly done:

你差不多完成了:

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 After all, you have me entagled with this silly group_by approach. Everything is just easier.

UPD毕竟,你让我迷上了这种愚蠢的group_by方法。一切都变得更容易。

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

#2


Here is another way, after using #group_by :

使用#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"}]

#3


Here are a couple of variants of the above.

以下是上述的几个变体。

Using 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"}]

Using Hash#update (aka merge!)

使用哈希#update(又名合并!)

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"}]

#1


You are nearly done:

你差不多完成了:

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 After all, you have me entagled with this silly group_by approach. Everything is just easier.

UPD毕竟,你让我迷上了这种愚蠢的group_by方法。一切都变得更容易。

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

#2


Here is another way, after using #group_by :

使用#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"}]

#3


Here are a couple of variants of the above.

以下是上述的几个变体。

Using 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"}]

Using Hash#update (aka merge!)

使用哈希#update(又名合并!)

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"}]