Как поменять ключи и значения в хэше?
У меня есть следующий хэш:
{:a=>:one, :b=>:two, :c=>:three}
что я хочу превратить в:
{:one=>:a, :two=>:b, :three=>:c}
Использование map
кажется довольно утомительным. Есть ли более короткое решение?
В Ruby есть вспомогательный метод для Hash, который позволяет вам обращаться с Hash, как если бы он был инвертирован (по сути, позволяя вам обращаться к ключам через значения):
{a: 1, b: 2, c: 3}.key(1)
=> :a
Если вы хотите сохранить инвертированный хеш, то Hash # invert должен работать в большинстве случаев:
{a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}
НО...
Если у вас есть повторяющиеся значения, invert
все ваши значения будут исключены, кроме последнего (потому что он будет продолжать заменять новое значение для этого ключа во время итерации). Аналогично, key
вернется только первый матч:
{a: 1, b: 2, c: 2}.key(2)
=> :b
{a: 1, b: 2, c: 2}.invert
=> {1=>:a, 2=>:c}
Итак, если ваши значения уникальны, вы можете использовать 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
Примечание: этот код с тестами теперь на GitHub .
Или:
class Hash
def safe_invert
self.each_with_object({}){|(k,v),o|(o[v]||=[])<<k}
end
end
each_with_object
имеет больше смысла, чем здесьinject
.each_with_object({}){ |i,o|k,v = *i; o[v] ||=[]; o[v] << k}
... приятноВы держите пари, что есть один! В Ruby всегда есть более короткий путь!
Это довольно просто, просто используйте
Hash#invert
:И вуаля!
источник
Это также будет обрабатывать повторяющиеся значения.
источник
Hash#inverse
дает тебе:тогда как встроенный
invert
метод просто сломан:источник
Использование массива
Использование хэша
источник
Если у вас есть хеш, где ключи уникальны, вы можете использовать Hash # invert :
Однако это не сработает, если у вас есть неуникальные ключи, где будут храниться только последние увиденные ключи:
Если у вас есть хеш с неуникальными ключами, вы можете сделать:
Если значения хэша уже являются массивами, вы можете сделать:
источник