Как изменить все ключи хэша на новый набор заданных клавиш?
Есть ли способ сделать это элегантно?
Как изменить все ключи хэша на новый набор заданных клавиш?
Есть ли способ сделать это элегантно?
В 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}
Предполагая, что у вас есть Hash
, который отображает старые ключи на новые ключи, вы можете сделать что-то вроде
hsh.map {|k, v| [key_map[k], v] }.to_h
Точное решение будет зависеть от формата, в котором у вас есть новые ключи (или если вы можете получить новый ключ из старого ключа.)
Предполагая, что у вас есть хеш 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
Другой способ сделать это:
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% рассчитывается с течением времени, поэтому подумайте об этом. Пара ответов не была включена, потому что есть потенциальные недостатки, когда они возвращают плохие результаты.
я предполагаю, что вы хотите изменить хэш- 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"
}
Если вы также беспокоитесь о производительности, это быстрее:
hsh.keys.each { |k| hsh[ key_map[k] ] = hsh.delete(k) if key_map[k] }
Вы не создаете новый хэш и переименовываете только нужные ключи. Это дает вам лучшую производительность.
Вы можете найти более подробную информацию в разделе Как элегантно переименовать все ключи в хеше в Ruby?"
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}