如果arr 是您的哈希数组,我建议:
代码
def combine(arr)
arr.each_with_object({}) { |g,h|
g.each { |k,v| (h[k] ||=[]) << v } }.map { |k,v| [k,*v] }
end
也可以写成:
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
示例
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"]]
说明
g.each { |k,v| (h[k] ||=[]) << v } }
将arr 中每个散列g 的键值对添加到初始为空的散列h。对于k,v 中的每一个键值对,如果h 具有键k,则h 中的该键的值将是一个数组,因此我们执行:
(h[k] ||= []) << v
#=> (h[k] = h[k] || []) << v
#=> (h[k] = h[k]) << v
#=> h[k] << v
但是,如果 h 没有那个密钥,h[k] => nil,那么:
(h[k] ||= []) << v
#=> (h[k] = nil || []) << v
#=> (h[k] = []) << v
#=> h[k] = [v]
我们首先创建哈希:
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"]}
然后将其转换为所需的数组:
hash.map { |k,v| [k,*v] }
#=> [[:fake, "bar", "object"], [:test, "me", "foo"], [:other, "here", "okay"]]
替代方案
这是另一种方式:
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
这使用Hash#update(又名merge!)的形式,它使用一个块来解析存在于被合并的两个哈希中的键的值。
在合并之前,每个哈希都被转换为一个哈希,其键相同,其值是这些值的数组。例如,
g = {
fake: "bar",
test: "me",
other: "here"
}
转换为:
g.merge(g) { |*_,v| [v] }
#=> {
# fake: ["bar"],
# test: ["me"],
# other: ["here"]
# }
这为我们提供了与第一种方法产生的相同的哈希值,并使用相同的代码将其转换为数组。