GeoCom
GeoCom

Reputation: 1374

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

Upvotes: 1

Views: 277

Answers (4)

iGian
iGian

Reputation: 11183

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? }.

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

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

Upvotes: 5

sawa
sawa

Reputation: 168081

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]]]
# ]

Upvotes: 4

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

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

Upvotes: 7

Related Questions