我需要这个哈希
{"peter" => ["apple", "orange", "mango"], "sandra" => ["flowers", "bike"]}
转换为此数组:
[["peter", "apple"], ["peter", "orange"], ["peter", "mango"], ["sandra", "flowers"], ["sandra", "bike"]]
现在我有了这个解决方案
my_hash.inject([]){|ar, (k,v)| ar << v.map{|c| [k,c]}}.flatten(1)
但我相信这里有zip
或transpose
magick更优雅的解决方案:)
答案 0 :(得分:5)
您对Enumerable#inject
解决方案持怀疑态度。在Ruby中,inject/reduce
有点滥用,我们必须小心并选择正确的抽象(map,select,zip,flatten ......),如果它们适合手头的问题。在这种情况下:
h = {"peter" => ["apple", "orange", "mango"], "sandra" => ["flowers", "bike"]}
h.map { |k, vs| vs.map { |v| [k, v] } }.flatten(1)
#=> [["peter", "apple"], ["peter", "orange"], ["peter", "mango"], ["sandra", "flowers"], ["sandra", "bike"]]
但是如果你想使用Enumerable#zip
,不要让任何人阻止你; - )
h.map { |k, vs| [k].cycle(vs.size).zip(vs) }.flatten(1)
正如@steenslag所说:
h.map { |k, vs| [k].product(vs) }.flatten(1)
所以最后我们可以写:
h.flat_map { |k, vs| [k].product(vs) }
答案 1 :(得分:2)
h.inject([]){|a,(k,vs)| a+vs.map {|v| [k,v]}}
您也可以使用此版本
h.inject([]){|a,(k,vs)| a+=vs.map {|v| [k,v]}}
哪个是最有效的,因为它使用相同的列表而不是在每次迭代时创建一个新列表。但是(对我来说)使用inject
并修改变量是错误的。 each
版本也会这样做。
a = []; h.each {|k,vs| a+=vs.map {|v| [k,v]}}
它略短且具有表现力。
答案 2 :(得分:1)
使用zip
hash.inject([]){ |ar, (k,v)| ar << ([k]*v.size).zip(v) }
使用transpose
的合理解决方案:
[
hash.keys.map{|k| [k]*hash[k].size }.flatten,
hash.keys.map{|k| hash[k] }.flatten
].transpose
考虑到:
hash.keys
应该在两种情况下以相同的顺序返回密钥,因此除非您确定,否则不要将其用于其他语言。