反转具有数组值的哈希表

8
为了方便撰写,我将我的哈希写成这样:
h = {
    :key1: [:val1, :val2, :val3],
    :key2: [:val4, :val5, :val6]
}

但是无论在哪里使用它,我都需要查找与值相关联的键。目前我正在执行以下操作进行转换:

h = Hash[*{
    :key1: [:val1, :val2, :val3],
    :key2: [:val4, :val5, :val6]
}.map {|key, vals| vals.map {|val| [val, key]}}.flatten]

这会给我想要的:

{ :val1 => :key1, :val2 => key1, :val3 => key1, :val4 => key2, :val5 => :key2, :val6 => :key2 }

但是有没有更简单的方法来实现同样的目标呢?
3个回答

10

使用Array#product非常强大。 :)

h = {
    key1: [:val1, :val2, :val3],
    key2: [:val4, :val5, :val6]
}

p Hash[h.flat_map {|k,v| v.product [k]}]
# {:val1=>:key1, :val2=>:key1, :val3=>:key1, :val4=>:key2, :val5=>:key2, :val6=>:key2}

我认为与其他方案相比,这是一种可读性和效率都很高的解决方案。 - Bastien D

3
h = {
    :key1 => [:val1, :val2, :val3],
    :key2 => [:val4, :val5, :val6]
}

p Hash[h.flat_map{|k,v| v.zip [k]*v.size }]
# >> {:val1=>:key1, :val2=>:key1, :val3=>:key1, :val4=>:key2, :val5=>:key2, :val6=>:key2}
p Hash[h.flat_map{|k,v| v.zip [k].cycle }]
# >> {:val1=>:key1, :val2=>:key1, :val3=>:key1, :val4=>:key2, :val5=>:key2, :val6=>:key2}

我认为这段代码很难阅读(因此,在生产系统中很难维护)。但它很酷,而且很短 :) (+1) - tessi
2
非常酷。v.zip([k]*v.size) 可以简化为 v.zip([k].cycle) - undur_gongor
@undur_gongor 今天我看到了一个很好的#cycle使用案例。非常感谢你。 - Arup Rakshit

2
我昨天也试图做这件事。这是我的解决方案:
h = {
key1: [:val1, :val2, :val3],    
key2: [:val4, :val5, :val6],    
}  
=> {:key1=>[:val1, :val2, :val3], :key2=>[:val4, :val5, :val6]}

hp = {}
=> {}

h.each { |k, v| v.each{ |e| hp[e] = k } }
=> {:key1=>[:val1, :val2, :val3], :key2=>[:val4, :val5, :val6]}

hp
=> {:val1=>:key1,
:val2=>:key1,
:val3=>:key1,
:val4=>:key2,
:val5=>:key2,
:val6=>:key2}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接