如何通过一组新的给定键更改哈希的所有键

时间:2010-10-28 15:32:38

标签: ruby hash

如何通过一组新的给定键更改哈希的所有键?

有没有办法优雅地做到这一点?

7 个答案:

答案 0 :(得分:77)

假设您有一个Hash将旧密钥映射到新密钥,您可以执行类似

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

答案 1 :(得分:7)

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} 

您也可以使用symbol#toproc。例如:

h.transform_keys! &:to_s
# => {"a"=>1, "b"=>2, "c"=>3}

答案 2 :(得分: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

答案 3 :(得分:3)

另一种方法是:

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}

这是基准时间......

虽然我喜欢Jörn答案的简单性,但我不确定它是否应该如此快,然后我看到了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%会随着时间的推移而得到回报所以请考虑一下。没有包括几个答案,因为存在潜在的缺陷,他们会返回不良结果。

答案 4 :(得分:3)

我假设您想要更改哈希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"
}

答案 5 :(得分:0)

如果您还担心性能问题,这会更快:

...
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
    os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
                               'drive-python-quickstart.json')

store = oauth2client.file.Storage(credential_path)
credentials = store.get()
...

您没有创建新的哈希,只重命名必要的密钥。这会让你获得更好的表现。

您可以在" How to elegantly rename all keys in a hash in Ruby?"

中找到更多详情

答案 6 :(得分:0)

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}