If arr is an array of your hashes, I would suggest:
Code
def combine(arr)
arr.each_with_object({}) { |g,h|
g.each { |k,v| (h[k] ||=[]) << v } }.map { |k,v| [k,*v] }
end
which can alternatively be written:
def combine(arr)
arr.each_with_object(Hash.new {|h,k| h[k]=[]}) { |g,h|
g.each { |k,v| h[k] << v } }.map { |k,v| [k,*v] }
end
Example
arr = [
{
fake: "bar",
test: "me",
other: "here"
},
{
fake: "object",
test: "foo",
other: "okay"
}
]
h = combine(arr)
#=> [[:fake, "bar", "object"], [:test, "me", "foo"],
# [:other, "here", "okay"]]
Explanation
g.each { |k,v| (h[k] ||=[]) << v } }
adds the key value pairs of each hash g in arr to an initially empty hash h. For each of those key-value pairs k,v, if h has the key k, the value of that key in h will be an array, so we execute:
(h[k] ||= []) << v
#=> (h[k] = h[k] || []) << v
#=> (h[k] = h[k]) << v
#=> h[k] << v
If, however, h does not have that key, h[k] => nil, so:
(h[k] ||= []) << v
#=> (h[k] = nil || []) << v
#=> (h[k] = []) << v
#=> h[k] = [v]
We first create the hash:
hash = arr.each_with_object(Hash.new {|h,k| h[k]=[]}) { |g,h|
g.each { |k,v| h[k] << v } }
#=> {:fake=>["bar", "object"], :test=>["me", "foo"],
# :other=>["here", "okay"]}
and then convert it to the desired array:
hash.map { |k,v| [k,*v] }
#=> [[:fake, "bar", "object"], [:test, "me", "foo"], [:other, "here", "okay"]]
Alternative
Here's another way:
def combine(arr)
arr.each_with_object({}) { |g,h|
h.update(g.merge(g) { |*_,v| [v] }) { |_,ov,nv| ov + nv } }
.map { |k,v| [k,*v] }
end
This uses the form of Hash#update (aka merge!) that uses a block to resolve the values of keys that are present in both the hashes being merged.
Before being merged, each hash is converted to a hash whose keys are the same and whose values are arrays of those values. For example,
g = {
fake: "bar",
test: "me",
other: "here"
}
is converted to:
g.merge(g) { |*_,v| [v] }
#=> {
# fake: ["bar"],
# test: ["me"],
# other: ["here"]
# }
This gives us the same hash as that produced by the first method, and uses the same code to convert it to an array.