Как заменить хеш-ключ другим ключом

136

У меня есть условие, когда я получаю хеш

  hash = {"_id"=>"4de7140772f8be03da000018", .....}

и я хочу, чтобы этот хеш был

  hash = {"id"=>"4de7140772f8be03da000018", ......}

P.S: я не знаю, какие ключи в хэше, они случайны, которые поставляются с префиксом "_" для каждого ключа, и я не хочу подчеркивания

Показать ещё 2 комментария
Теги:
hash
ruby-on-rails-3

7 ответов

27
Лучший ответ

Если все ключи являются строками, и все они имеют префикс подчеркивания, вы можете исправить хэш на месте с помощью этого:

h.keys.each { |k| h[k[1, k.length - 1]] = h[k]; h.delete(k) }

k[1, k.length - 1] бит захватывает все k, кроме первого символа. Если вы хотите получить копию, то:

new_h = Hash[h.map { |k, v| [k[1, k.length - 1], v] }]

или

new_h = h.inject({ }) { |x, (k,v)| x[k[1, k.length - 1]] = v; x }

Вы также можете использовать sub, если вам не нравится нотация k[] для извлечения подстроки:

h.keys.each { |k| h[k.sub(/\A_/, '')] = h[k]; h.delete(k) }
Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

И если только некоторые из клавиш имеют префикс подчеркивания:

h.keys.each do |k|
    if(k[0,1] == '_')
        h[k[1, k.length - 1]] = h[k]
        h.delete(k)
    end
end

Аналогичные модификации могут быть сделаны ко всем другим вариантам выше, но эти два:

Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

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

  • 0
    твой ответ сработал, но после прихода я нашел несколько таких хешей
  • 3
    {"_id" => "4de7140772f8be03da000018", "_type" => "WorkStation", "creation_at" => "2011-06-02T10: 24: 35 + 05: 45", "input_header_ids" => [], "line_id "=>" 4de7140472f8be03da000017 "," updated_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Показать ещё 21 комментарий
548
hash[:new_key] = hash.delete :old_key
  • 8
    Спасли мне пару LOC, люблю это!
  • 64
    Это должен быть принятый ответ!
Показать ещё 17 комментариев
84

rails У хэша есть стандартный метод для него:

hash.transform_keys{ |key| key.to_s.upcase }

http://api.rubyonrails.org/classes/Hash.html#method-i-transform_keys

  • 3
    Это метод Rails, а не стандартный. Хороший ответ, хотя.
  • 0
    спасибо я отредактировал ответ
Показать ещё 5 комментариев
13

вы можете сделать

hash.inject({}){|option, (k,v) | option["id"] = v if k == "_id"; option}

Это должно работать на ваш случай!

  • 4
    Ваш код работает только для идентификатора, но не заменяет ключи ....
  • 0
    но в любом случае мое предложение по инъекции сработало;)
Показать ещё 1 комментарий
9
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }
  • 4
    Мне нравится, что вы пытались использовать регулярное выражение для правильной фильтрации подчеркивания, но вы должны знать, что в ruby, в отличие от javascript и других, / ^ / означает «начало строки ИЛИ LINE», а / $ / означает «конец Строка ИЛИ ЛИНИЯ. В этом случае маловероятно, что в ключах есть символы новой строки, но вы должны знать, что использование этих двух операторов в ruby не только подвержено ошибкам, но и очень опасно, если их неправильно использовать при проверках на инъекции. Смотрите здесь для объяснения. Надеюсь, вы не против распространять информацию.
7

Если мы хотим переименовать конкретный ключ в хэш, мы можем сделать это следующим образом:
Предположим, что мой хэш my_hash = {'test' => 'ruby hash demo'}
Теперь я хочу заменить 'test' на 'message', затем:
my_hash['message'] = my_hash.delete('test')

  • 0
    Как ваш ответ является тогда решением моей проблемы? Если вы считаете, что это было полезно, то вы могли бы добавить в комментарий под вопросом. Мой вопрос не состоял в том, чтобы заменить ключ другим ключом, решение, которое вы дали, является очень простым свойством Hash. в моем случае это не: hash[:new_key] = has[:old_key] , вместо этого это: hash[:dynamic_key] = hash[:_dynamic_key] , это был ясный вопрос о регулярном выражении, а не простая замена хеша.
  • 2
    Я пришел к этому через поиск в Google и хотел получить ответ @ Swapnil. Спасибо
1
hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню