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

Как изменить все ключи хэша на новый набор заданных ключей

Как изменить все ключи хэша на новый набор заданных клавиш?

Есть ли способ сделать это элегантно?

4b9b3361

Ответ 1

В Ruby 2.5 есть Hash # transform_keys! метод. Пример использования карты ключей

h = {a: 1, b: 2, c: 3}
key_map = {a: 'A', b: 'B', c: 'C'}

h.transform_keys! {|k| key_map[k]}
# => {"A"=>1, "B"=>2, "C"=>3} 

Вы также можете использовать символ # toproc ярлык с transform_keys Например:

h.transform_keys! &:upcase
# => {"A"=>1, "B"=>2, "C"=>3}

Ответ 2

Предполагая, что у вас есть Hash, который отображает старые ключи на новые ключи, вы можете сделать что-то вроде

hsh.map {|k, v| [key_map[k], v] }.to_h

Ответ 3

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

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

h.keys.each do |key|
  h[new_keys[key]] = h[key] # add entry for new key
  k.delete(key)             # remove old key
end

Ответ 4

Другой способ сделать это:

hash = {
  'foo' => 1,
  'bar' => 2
}

new_keys = {
  'foo' => 'foozle',
  'bar' => 'barzle'
}

new_keys.values.zip(hash.values_at(*new_keys.keys)).to_h 
# => {"foozle"=>1, "barzle"=>2}

Разрушение:

new_keys
.values # => ["foozle", "barzle"]
.zip(
  hash.values_at(*new_keys.keys) # => [1, 2]
) # => [["foozle", 1], ["barzle", 2]]
.to_h 
# => {"foozle"=>1, "barzle"=>2}

Это контрольное время...

Хотя мне нравится простота ответа Йорна, я не был уверен, что это так быстро, как должно быть, тогда я увидел комментарий selvamani:

require 'fruity'

HASH = {
  'foo' => 1,
  'bar' => 2
}

NEW_KEYS = {
  'foo' => 'foozle',
  'bar' => 'barzle'
}

compare do
  mittag    { HASH.dup.map {|k, v| [NEW_KEYS[k], v] }.to_h }
  ttm       { h = HASH.dup; NEW_KEYS.values.zip(h.values_at(*NEW_KEYS.keys)).to_h }
  selvamani { h = HASH.dup; h.keys.each { |key| h[NEW_KEYS[key]] = h.delete(key)}; h }
end

# >> Running each test 2048 times. Test will take about 1 second.
# >> selvamani is faster than ttm by 39.99999999999999% ± 10.0%
# >> ttm is faster than mittag by 10.000000000000009% ± 10.0%

Они работают очень близко друг к другу, поэтому каждый будет делать, но 39% рассчитывается с течением времени, поэтому подумайте об этом. Пара ответов не была включена, потому что есть потенциальные недостатки, когда они возвращают плохие результаты.

Ответ 5

я предполагаю, что вы хотите изменить хэш- keys без изменения значений:

hash = {
   "nr"=>"123",
   "name"=>"Herrmann Hofreiter",
   "pferd"=>"010 000 777",
   "land"=>"hight land"
}
header = ["aa", "bb", "cc", "dd"]
new_hash = header.zip(hash.values).to_h

Результат:

{
   "aa"=>"123",
   "bb"=>"Herrmann Hofreiter",
   "cc"=>"010 000 777",
   "dd"=>"high land"
}

Ответ 6

Если вы также беспокоитесь о производительности, это быстрее:

hsh.keys.each { |k| hsh[ key_map[k] ] = hsh.delete(k) if key_map[k] }

Вы не создаете новый хэш и переименовываете только нужные ключи. Это дает вам лучшую производительность.

Вы можете найти более подробную информацию в разделе Как элегантно переименовать все ключи в хеше в Ruby?"

Ответ 7

h = { 'foo'=>1, 'bar'=>2 }
key_map = { 'foo'=>'foozle', 'bar'=>'barzle' }

h.each_with_object({}) { |(k,v),g| g[key_map[k]]=v }
  #=> {"foozle"=>1, "barzle"=>2}

или

h.reduce({}) { |g,(k,v)| g.merge(key_map[k]=>v) }
  #=> {"foozle"=>1, "barzle"=>2}