将数组的哈希变成Ruby中的哈希数组

时间:2009-10-29 00:27:51

标签: ruby arrays hash

我们有以下数据结构:

{:a => ["val1", "val2"], :b => ["valb1", "valb2"], ...}

我想把它变成

[{:a => "val1", :b => "valb1"}, {:a => "val2", :b => "valb2"}, ...]

然后回到第一个表格。任何看起来很漂亮的人?

7 个答案:

答案 0 :(得分:12)

此解决方案适用于任意数量的值(val1,val2 ... valN):

{:a => ["val1", "val2"], :b => ["valb1", "valb2"]}.inject([]){|a, (k,vs)| 
  vs.each_with_index{|v,i| (a[i] ||= {})[k] = v} 
  a
}
# => [{:a=>"val1", :b=>"valb1"}, {:a=>"val2", :b=>"valb2"}]

[{:a=>"val1", :b=>"valb1"}, {:a=>"val2", :b=>"valb2"}].inject({}){|a, h| 
  h.each_pair{|k,v| (a[k] ||= []) << v}
  a
}
# => {:a=>["val1", "val2"], :b=>["valb1", "valb2"]}

答案 1 :(得分:7)

使用功能方法(参见Enumerable):

hs = h.values.transpose.map { |vs| h.keys.zip(vs).to_h }
#=> [{:a=>"val1", :b=>"valb1"}, {:a=>"val2", :b=>"valb2"}]

然后回来:

h_again = hs.first.keys.zip(hs.map(&:values).transpose).to_h
#=> {:a=>["val1", "val2"], :b=>["valb1", "valb2"]}

答案 2 :(得分:1)

让我们仔细看看我们试图在哪些数据结构之间进行转换:

#Format A
[
 ["val1", "val2"],          :a
 ["valb1", "valb2"],        :b 
 ["valc1", "valc2"]         :c 
]
#Format B
[ :a        :b       :c
 ["val1", "valb1", "valc1"],
 ["val2", "valb2", "valc3"]
]

发现Format B是必不可少的Format A的转置并不是很困难,那么我们就可以提出这个解决方案:

h={:a => ["vala1", "vala2"], :b => ["valb1", "valb2"], :c => ["valc1", "valc2"]}
sorted_keys =  h.keys.sort_by {|a,b| a.to_s <=> b.to_s}

puts sorted_keys.inject([])  {|s,e| s << h[e]}.transpose.inject([])   {|r, a| r << Hash[*sorted_keys.zip(a).flatten]}.inspect
#[{:b=>"valb1", :c=>"valc1", :a=>"vala1"}, {:b=>"valb2", :c=>"valc2", :a=>"vala2"}]

答案 3 :(得分:1)

m = {}
a,b = Array(h).transpose
b.transpose.map { |y| [a, y].transpose.inject(m) { |m,x| m.merge Hash[*x] }}

答案 4 :(得分:1)

我的尝试,也许稍微紧凑。

h = { :a => ["val1", "val2"], :b => ["valb1", "valb2"] }

h.values.transpose.map { |s| Hash[h.keys.zip(s)] }

应该在Ruby 1.9.3或更高版本中运行。


说明:

首先,将相应的值“组合”为“行”

h.values.transpose
# => [["val1", "valb1"], ["val2", "valb2"]] 

map块中的每次迭代都会产生以下一种:

h.keys.zip(s)
# => [[:a, "val1"], [:b, "valb1"]]

Hash[]会将它们变为哈希:

Hash[h.keys.zip(s)]
# => {:a=>"val1", :b=>"valb1"}      (for each iteration)

答案 5 :(得分:0)

您可以使用inject来构建哈希数组。

hash = { :a => ["val1", "val2"], :b => ["valb1", "valb2"] }
array = hash.inject([]) do |pairs, pair|
  pairs << { pair[0] => pair[1] }
  pairs
end
array.inspect # => "[{:a=>["val1", "val2"]}, {:b=>["valb1", "valb2"]}]"

Ruby文档有few more examples使用inject

答案 6 :(得分:0)

这将有效,假设原始哈希中的所有数组都是相同的大小:

hash_array = hash.first[1].map { {} }
hash.each do |key,arr|
  hash_array.zip(arr).each {|inner_hash, val| inner_hash[key] = val}
end