ruby 如何在散列中交换键和值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10989259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to swap keys and values in a hash
提问by Jonathan Allard
How do I swap keys and values in a Hash?
如何交换哈希中的键和值?
I have the following Hash:
我有以下哈希:
{:a=>:one, :b=>:two, :c=>:three}
that I want to transform into:
我想变成:
{:one=>:a, :two=>:b, :three=>:c}
Using mapseems rather tedious. Is there a shorter solution?
使用起来map似乎相当乏味。有更短的解决方案吗?
回答by Nigel Thorne
Ruby has a helper method for Hash that lets you treat a Hash as if it was inverted (in essence, by letting you access keys through values):
Ruby 有一个 Hash 的辅助方法,可以让您将 Hash 视为反转(本质上,通过让您通过值访问键):
{a: 1, b: 2, c: 3}.key(1)
=> :a
If you want to keep the inverted hash, then Hash#invertshould work for most situations:
如果您想保留反向散列,那么Hash#invert应该适用于大多数情况:
{a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}
BUT...
但...
If you have duplicate values, invertwill discard all but the last occurrence of your values (because it will keep replacing new value for that key during iteration). Likewise, keywill only return the first match:
如果您有重复的值,invert将丢弃除最后一次出现的值之外的所有值(因为它会在迭代期间不断替换该键的新值)。同样,key只会返回第一个匹配项:
{a: 1, b: 2, c: 2}.key(2)
=> :b
{a: 1, b: 2, c: 2}.invert
=> {1=>:a, 2=>:c}
So, if your values are unique you can use Hash#invert. If not, then you can keep all the values as an array, like this:
因此,如果您的值是唯一的,则可以使用Hash#invert. 如果没有,那么您可以将所有值保留为一个数组,如下所示:
class Hash
# like invert but not lossy
# {"one"=>1,"two"=>2, "1"=>1, "2"=>2}.inverse => {1=>["one", "1"], 2=>["two", "2"]}
def safe_invert
each_with_object({}) do |(key,value),out|
out[value] ||= []
out[value] << key
end
end
end
Note: This code with tests is now on GitHub.
注意:这个带有测试的代码现在在 GitHub 上。
Or:
或者:
class Hash
def safe_invert
self.each_with_object({}){|(k,v),o|(o[v]||=[])<<k}
end
end
回答by Jonathan Allard
You bet there is one! There is always a shorter way to do things in Ruby!
你打赌有一个!在 Ruby 中总是有一种更短的方式来做事!
It's pretty simple, just use Hash#invert:
这很简单,只需使用Hash#invert:
{a: :one, b: :two, c: :three}.invert
=> {:one=>:a, :two=>:b, :three=>:c}
Et voilà!
等等!
回答by Riaze
files = {
'Input.txt' => 'Randy',
'Code.py' => 'Stan',
'Output.txt' => 'Randy'
}
h = Hash.new{|h,k| h[k] = []} # Create hash that defaults unknown keys to empty an empty list
files.map {|k,v| h[v]<< k} #append each key to the list at a known value
puts h
This will handle the duplicate values too.
这也将处理重复值。
回答by dawg
If you have a hash where are the keys are unique, you can use Hash#invert:
如果您有一个哈希,其中键是唯一的,您可以使用Hash#invert:
> {a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}
That won't work if you have non unique keys, however, where only the last keys seen will be kept:
但是,如果您有非唯一键,这将不起作用,但是,只会保留最后看到的键:
> {a: 1, b: 2, c: 3, d: 3, e: 2, f: 1}.invert
=> {1=>:f, 2=>:e, 3=>:d}
If you have a hash with non unique keys, you might do:
如果你有一个非唯一键的哈希,你可以这样做:
> hash={a: 1, b: 2, c: 3, d: 3, e: 2, f: 1}
> hash.each_with_object(Hash.new { |h,k| h[k]=[] }) {|(k,v), h|
h[v] << k
}
=> {1=>[:a, :f], 2=>[:b, :e], 3=>[:c, :d]}
If the values of the hash are already arrays, you can do:
如果散列的值已经是数组,则可以执行以下操作:
> hash={ "A" => [14, 15, 16], "B" => [17, 15], "C" => [35, 15] }
> hash.each_with_object(Hash.new { |h,k| h[k]=[] }) {|(k,v), h|
v.map {|t| h[t] << k}
}
=> {14=>["A"], 15=>["A", "B", "C"], 16=>["A"], 17=>["B"], 35=>["C"]}
回答by Tilo
# this doesn't looks quite as elegant as the other solutions here,
# but if you call inverse twice, it will preserve the elements of the original hash
# true inversion of Ruby Hash / preserves all elements in original hash
# e.g. hash.inverse.inverse ~ h
class Hash
def inverse
i = Hash.new
self.each_pair{ |k,v|
if (v.class == Array)
v.each{ |x|
i[x] = i.has_key?(x) ? [k,i[x]].flatten : k
}
else
i[v] = i.has_key?(v) ? [k,i[v]].flatten : k
end
}
return i
end
end
Hash#inversegives you:
Hash#inverse给你:
h = {a: 1, b: 2, c: 2}
h.inverse
=> {1=>:a, 2=>[:c, :b]}
h.inverse.inverse
=> {:a=>1, :c=>2, :b=>2} # order might not be preserved
h.inverse.inverse == h
=> true # true-ish because order might change
whereas the built-in invertmethod is just broken:
而内置invert方法刚刚被破坏:
h.invert
=> {1=>:a, 2=>:c} # FAIL
h.invert.invert == h
=> false # FAIL
回答by Prashant Ravi Darshan
Using Array
使用数组
input = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4", :key5=>"value5"}
output = Hash[input.to_a.map{|m| m.reverse}]
Using Hash
使用哈希
input = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4", :key5=>"value5"}
output = input.invert

