Обратный хэш в Ruby
Как бы я мог отменить элементы хэша, сохранив те же значения и ключи, но изменив их порядок в хеше.
Так же:
{ "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
И преобразуем это в:
{ "1" => "spider", "lala" => "54", "10" => "cool", "4" => "happiness" }
Или, возможно, я мог бы запустить цикл each
назад, начиная с последнего элемента хэша, а не из первого?
Ответы
Ответ 1
Вы можете преобразовать хэш в массив, отменить это, а затем преобразовать обратно в хэш:
reversed_h = Hash[h.to_a.reverse]
Hash#to_a
дает массив массивов, внутренние массивы - простые пары [key,value]
, тогда вы отменяете этот массив, используя Array#reverse
, а Hash[]
преобразует пары [key,value]
обратно в хэш.
Ruby 2.1 добавляет метод Array#to_h
, поэтому теперь вы можете сказать:
reversed_h = h.to_a.reverse.to_h
Ответ 2
В Ruby 2.1+ вы можете комбинировать reverse_each
и to_h
:
{foo: 1, bar: 2}.reverse_each.to_h
#=> {:bar=>2, :foo=>1}
Ответ 3
hash = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
reversed_hash = Hash[hash.to_a.reverse]
Ответ 4
h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
p Hash[h.reverse_each.map{|e| e}]
#=> {"1"=>"spider", "lala"=>"54", "10"=>"cool", "4"=>"happiness"}
Но это оставляет плохой вкус (точно так же, как и другие ответы, которые отлично работают, как этот). Если вам нужно это сделать, это может быть признаком того, что Хэш не был лучшим выбором.
Ответ 5
reversed_h = Hash[h.to_a.collect(&:reverse)]
Ответ 6
В качестве альтернативы вы можете использовать reduce
и merge
, чтобы добавить элемент в новый хэш:
hash = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
hash.reduce({}){ |memo, object| Hash[*object].merge(memo) }
но это безумие: D
Ответ 7
В Ruby 1.8.7 порядок элементов в хэше документируется не под нашим контролем, поэтому ни один из вышеперечисленных методов Работа. В Ruby 1.9.3 все работает и документируется так, как полагаются другие ответы.
$ irb1.8
h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
Hash[h.to_a().reverse()]
=> {"lala"=>"54", "1"=>"spider", "10"=>"cool", "4"=>"happiness"}
quit
$ irb1.9.1
h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }
Hash[h.to_a().reverse()]
=>{"1"=>"spider", "lala"=>"54", "10"=>"cool", "4"=>"happiness"}
Путь Ruby 1.8.7 был настолько укоренен для меня, что я неправильно понял этот вопрос в течение некоторого времени. Я думал, что он запросил способ Hash # инвертировать: т.е. Преобразовать хэш, чтобы диапазон отображался в домене. Этот метод отбрасывает дубликаты. Луис Рамальо предлагает метод, который не делает этого, но он немного неуклюж. Это немного короче:
$ irb
def invertWithDuplicates(original)
inverse = Hash.new() { |hash, key| hash[key] = []; }
original.each_pair() { |key, value| inverse[value].push(key); }
return inverse
end
h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "cool" }
invertWithDuplicates(h)
=> {"happiness"=>["4"], "cool"=>["1", "10"], "54"=>["lala"]}
Извините, что отклонился от темы, предназначенной для OP, хотя я утверждаю, что это соответствует заголовку сообщения "Обратный хэш в Ruby".