简体   繁体   中英

Merge two arrays in Ruby by unique key

How can I merge two arrays with the unique key :

keyList = ["a", "b", "c", "d"]

keyValueList = [
  ["a", [1, 2, 3]],
  ["a", [4, 5, 6]],
  ["b", [5, "a", 3]],
  ["b", ["test", 4, 3]],
  ["c", [1, "number", 110]]
]

to get the following?

[
  ["a", [[1, 2, 3], [4, 5, 6]]],
  ["b", [[5, "a", 3], ["test", 4, 3]]],
  ["c", [[1, "number", 110]]]
]

Use Enumerable#group_by :

keyValueList.
  map(&:flatten).
  group_by(&:shift).
  select { |k, _| keyList.include?(k) }.
  to_a
#⇒ [["a", [[1, 2, 3], [4, 5, 6]]],
#   ["b", [[5, "a", 3], ["test", 4, 3]]],
#   ["c", [[1, "number", 110]]]

It's not clear why the array keyList is needed.

keyValueList.each_with_object(Hash.new {|h,k| h[k]=[]}) do |(k,arr),h|
  h[k] << arr
end.to_a
  #=> [["a", [[1, 2, 3], [4, 5, 6]]],
  #    ["b", [[5, "a", 3], ["test", 4, 3]]],
  #    ["c", [[1, "number", 110]]]]

h[k] << arr could be changed to h[k] << arr if keyList.include?(k) if needed for the desired behavior.

The above could alternatively be written as follows.

keyValueList.each_with_object({}) do |(k,arr),h|
  (h[k] ||= []) << arr
end.to_a
keyValueList
.group_by(&:first)
.transform_values{|a| a.map(&:last)}
.to_a
# => [
#  ["a", [[1, 2, 3], [4, 5, 6]]],
#  ["b", [[5, "a", 3], ["test", 4, 3]]],
#  ["c", [[1, "number", 110]]]
# ]

Even though it does not appear in the expected result, I'd also take keyList into account, just in case, so:

keyList
.each_with_object({}) { |k, h| h[k] = keyValueList.select { |x, y| x == k }.map(&:last) }
.to_a

#=> [["a", [[1, 2, 3], [4, 5, 6]]], ["b", [[5, "a", 3], ["test", 4, 3]]], ["c", [[1, "number", 110]]], ["d", []]]

To get rid of ["d", []] , just append .reject{ |e| e.last.empty? } .reject{ |e| e.last.empty? } .reject{ |e| e.last.empty? } .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM