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

192

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

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

и я хочу этот хеш как

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

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

Маниш дас
источник
Это может вам помочь: stackoverflow.com/questions/4044451/…
разъедено
+1 за полезный вопрос
ashisrai_
@ a5his: Я рад, что это помогло :)
Маниш Дас

Ответы:

711
hash[:new_key] = hash.delete :old_key
gayavat
источник
8
Спасли мне пару LOC, люблю это!
nicohvi
10
Мне часто не нравится «умный» код ruby, потому что требуется время, чтобы понять, что он на самом деле делает. Ваше решение, с другой стороны, простое и описательное.
Лукас
3
Это действительно должен быть принятый ответ! Легко, чисто и прямо в точку!
GigaBass
1
Этот ответ элегантен, но на самом деле он не отвечает на вопрос. В сообщении говорится, что ключи, которые необходимо заменить, неизвестны ... Мы знаем только то, что они начинаются с подчеркивания, мы не знаем, что это за ключи на самом деле.
Дсел
2
таким образом, создается новая пара ключ / значение, в которой вы указываете новый ключ и получаете значение из hash.delete :old_keyвозвращаемого значения, а при удалении используется старый ключ. Ух ты, я хочу, чтобы это было где-то татуировано :-D Спасибо
Барт C
136

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

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

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

UPD: метод ruby ​​2.5

gayavat
источник
4
Это метод Rails, а не стандартный. Хороший ответ, хотя.
user2422869 14.10.15
1
Кроме того, этот метод не может рекурсивно работать с ключами хеша.
Серхио Белевский
5
Для этого можно использовать deep_transform_keys
gayavat
1
Наконец! Это именно то, что я искал!
ТиСер
4
Это стандартная часть языка начиная с
Дэвид Грейсон,
39

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

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 }

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

мю слишком коротка
источник
Ваш ответ сработал, но после прихода я нашел несколько таких хешей
Маниш Дас
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 "}
Маниш Дас
2
{"id" => "4de7140772f8be03da000018", "type" => "WorkStation", "reated_at" => "2011-06-02T10: 24: 35 + 05: 45", "nput_header_ids" => [], "ine_id "=>" 4de7140472f8be03da000017 "," pdated_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Маниш Дас
@Manish: я сказал: «Если все ключи являются строками и все они имеют префикс подчеркивания». Я включил примерный подход для ваших «ключей без префиксов подчеркивания» в обновлении.
мю слишком коротка
2
@Manish: «k» для «ключа», «v» для «значения», «x» для «я не знаю, как это назвать, но я учился на математика, поэтому я называю его х».
Му слишком коротка
14

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

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

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

Садикша Гаутам
источник
11

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

Свапнил чинчолкар
источник
Как ваш ответ является решением моей проблемы? Если вы считаете, что это было полезно, то вы могли бы добавить в комментарий под вопросом. Мой вопрос не состоял в том, чтобы заменить ключ другим ключом, решение, которое вы дали, является очень простым свойством Hash. в моем случае это не:, hash[:new_key] = has[:old_key]вместо этого:, hash[:dynamic_key] = hash[:_dynamic_key]это был ясный вопрос о регулярных выражениях, а не простая замена хеша.
Маниш Дас
2
Я пришел к этому через поиск в Google и хотел получить ответ @ Swapnil. Спасибо
toobulkeh
10
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }
DigitalRoss
источник
4
Мне нравится, что вы пытались использовать регулярное выражение для правильной фильтрации подчеркиваний, но вы должны знать, что в ruby, в отличие от javascript и других, / ^ / означает «начало строки ИЛИ LINE», а / $ / означает «конец Строка ИЛИ ЛИНИЯ. В этом случае маловероятно, что в ключах есть символы новой строки, но вы должны знать, что использование этих двух операторов в ruby ​​не только подвержено ошибкам, но и очень опасно, если их неправильно использовать при проверках на инъекции. Смотрите здесь для объяснения. Надеюсь, вы не против распространять информацию.
Йорн ван де Беек
2
hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}
maerics
источник
1

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

Примеры

Расширить класс хэша

Добавляет метод повторного ввода в экземпляры Hash.

# Adds additional methods to Hash
class ::Hash
  # Changes the keys on a hash
  # Takes a block that passes the current key
  # Whatever the block returns becomes the new key
  # If a hash is returned for the key it will merge the current hash 
  # with the returned hash from the block. This allows for nested rekeying.
  def rekey
    self.each_with_object({}) do |(key, value), previous|
      new_key = yield(key, value)
      if new_key.is_a?(Hash)
        previous.merge!(new_key)
      else
        previous[new_key] = value
      end
    end
  end
end

Пример Prepend

my_feelings_about_icecreams = {
  vanilla: 'Delicious',
  chocolate: 'Too Chocolatey',
  strawberry: 'It Is Alright...'
}

my_feelings_about_icecreams.rekey { |key| "#{key}_icecream".to_sym }
# => {:vanilla_icecream=>"Delicious", :chocolate_icecream=>"Too Chocolatey", :strawberry_icecream=>"It Is Alright..."}

Пример обрезки

{ _id: 1, ___something_: 'what?!' }.rekey do |key|
  trimmed = key.to_s.tr('_', '')
  trimmed.to_sym
end
# => {:id=>1, :something=>"what?!"}

Сглаживание и добавление "Scope"

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

people = {
  bob: {
    name: 'Bob',
    toys: [
      { what: 'car', color: 'red' },
      { what: 'ball', color: 'blue' }
    ]
  },
  tom: {
    name: 'Tom',
    toys: [
      { what: 'house', color: 'blue; da ba dee da ba die' },
      { what: 'nerf gun', color: 'metallic' }
    ]
  }
}

people.rekey do |person, person_info|
  person_info.rekey do |key|
    "#{person}_#{key}".to_sym
  end
end

# =>
# {
#   :bob_name=>"Bob",
#   :bob_toys=>[
#     {:what=>"car", :color=>"red"},
#     {:what=>"ball", :color=>"blue"}
#   ],
#   :tom_name=>"Tom",
#   :tom_toys=>[
#     {:what=>"house", :color=>"blue; da ba dee da ba die"},
#     {:what=>"nerf gun", :color=>"metallic"}
#   ]
# }
CTS_AE
источник
0

Предыдущие ответы достаточно хороши, но они могут обновить исходные данные. Если вы не хотите, чтобы исходные данные были затронуты, вы можете попробовать мой код.

 newhash=hash.reject{|k| k=='_id'}.merge({id:hash['_id']})

Сначала он игнорирует ключ '_id', затем объединяется с обновленным.

пурушотаман пуваи
источник