Подтвердить что ты не робот

Обратный хэш в Ruby

Как бы я мог отменить элементы хэша, сохранив те же значения и ключи, но изменив их порядок в хеше.

Так же:

{ "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" }

И преобразуем это в:

{ "1" => "spider", "lala" => "54", "10" => "cool", "4" => "happiness" }

Или, возможно, я мог бы запустить цикл each назад, начиная с последнего элемента хэша, а не из первого?

4b9b3361

Ответ 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".