Переименовать хэш-ключ, но сохранить порядок (без новой вставки)

Я хочу переименовать хэш-ключ. Этот:

myhash[preferred_name] = myhash.delete old_name 

вставляет новую пару значений ключа в последний индекс моего хэша. Есть ли способ переименовать хеш без добавления нового?

Когда я пробую ваше существующее решение, оно работает, как ожидалось. Один ключ удаляется, а значению дается новое имя. Какую версию Ruby вы используете?

AJFaraday 17.12.2018 17:44

да, это работает, но он вставит новый хеш в последний индекс, который мне не нравится. Я хочу сохранить порядок пар "ключ-значение" в моем хэше

stuckoverflow24 17.12.2018 17:46

Я не могу найти его легко, возможно, можно было бы перебрать и отбросить все параметры в новый хэш и изменить один с помощью select, но это очень быстро испортится. На всякий случай, вот методы, доступные для Hash docs.ruby-lang.org/en/2.0.0/Hash.html

AJFaraday 17.12.2018 17:54
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
1
3
88
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете использовать transform_keys!:

h = { foo: 1, bar: 2, baz: 3 }

h.transform_keys! { |k| k == :bar ? :qux : k }
#=> {:foo=>1, :qux=>2, :baz=>3}

Просто убедитесь, что нового ключа еще нет в хэше.

Я второй ответ @Stefen, при условии, что нет необходимости поддерживать версии Ruby до 2.5, когда Хешируйте # transform_keys! дебютировал. Если более ранние версии должны поддерживаться, вот один способ (который не создает новый хэш), расширение подхода, упомянутого OP.

h = { foo: 1, bar: 2, baz: 3 }

h.keys.each { |k| h[k == :bar ? :qux : k] = h.delete(k) }
  #=> [:foo, :bar, :baz] 
h #=> {:foo=>1, :qux=>2, :baz=>3}

Обратите внимание, что перечислители Хэш # each_key и Хэш # каждый нельзя использовать, потому что ключи удаляются во время итерации.

Другой выбор следующий.

keys = h.keys
keys[keys.index(:bar)] = :qux
h.replace(keys.zip(h.values).to_h)
  #=> {:foo=>1, :qux=>2, :baz=>3}
myhash.to_a.each { |a| a[0] = preferred_name if a[0] == old_name }.to_h

Или:

h.map { |k, v| [k == old_name ? preferred_name : k, v] }.to_h

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

Другие вопросы по теме