我有像这样的红宝石哈希(大约20个键/值除外):
{
fake: "bar",
test: "me",
other: "here"
}
{
fake: "object",
test: "foo",
other: "okay"
}
我需要从这些哈希中创建一个二维数组,如下所示:
[
["fake", "bar", "object"],
["test", "me", "foo"]
]
我考虑为每个键创建一个数组并循环遍历对象以推送它们的值:
fake_array = ["fake"]
items.each do |i|
fake_array << i[:fake]
end
这意味着为每个阵列创建一个数组(虽然大约20个),并将属性推送到各自的数组。这看起来很愚蠢 - 我认为有一种更清洁的方法可以做到这一点。帮助
答案 0 :(得分:2)
如果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 } }
将g
中每个哈希值arr
的键值对添加到最初为空的哈希值h
。对于每个键值对k,v
,如果h
具有键k
,则h
中该键的值将为数组,因此我们执行:< / p>
(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"]
# }
这给我们提供了与第一种方法相同的哈希值,并使用相同的代码将其转换为数组。
答案 1 :(得分:0)
h1 = {
fake: "bar",
test: "me",
other: "here"
}
h2 = {
fake: "object",
test: "foo",
other: "okay"
}
arr = []
h1.merge(h2){|k,o,n| [k.to_s,o,n]}.each_value{ |v| arr << v}
(main):0 > arr
=> [["fake", "bar", "object"], ["test", "me", "foo"], ["other", "here", "okay"]]
答案 2 :(得分:0)
试试这个:
require 'pp'
def hash_to_arr(arr_of_hashes)
temp_hash = {}
arr_of_hashes.each do |hash|
hash.each do |k,v|
ks = k.to_s
if(temp_hash[ks])
temp_hash[ks] << v
else
temp_hash[ks] = [v]
end
end
end
result = []
temp_hash.each do |k,v|
result << [k, *v]
end
result
end
pp hash_to_arr [
{
fake: "bar",
test: "me",
other: "here"
},
{
fake: "object",
test: "foo",
other: "okay"
}
]
# => [["fake", "bar", "object"], ["test", "me", "foo"], ["other", "here", "okay"]]
答案 3 :(得分:0)
这是一个简洁的,我认为你做的是你所追求的。给定哈希值X1,X2,... Xn
result = []
x1.zip(x2, xn) { |arr| result << arr.flatten.uniq.map(&:to_s) }
答案 4 :(得分:0)
在Ruby 1.9或更高版本中,哈希是有序的。如果你预先订购/对齐你的两个哈希,你可以这样做:
a = {:fake=>"bar", :test=>"me", :other=>"here"}
b = {:fake=>"object", :test=>"foo", :other=>"okay"}
a.keys.zip(a.values,b.values)
=&GT; [[:fake,&#34; bar&#34;,&#34; object&#34;],[:test,&#34; me&#34;,&#34; foo&#34;],[:other ,&#34;这里&#34;,&#34;好的&#34;]]