如何用另一个键替换哈希键


191

我有一个条件,我得到一个哈希

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

我希望此哈希为

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

PS:我不知道哈希中的键是什么,它们是随机的,每个键都带有“ _”前缀,我不希望有下划线



+1有用的问题
ashisrai_

@ a5his:很高兴能为您提供帮助:)
Manish Das

Answers:


709
hash[:new_key] = hash.delete :old_key

8
为我省了几分LOC,喜欢它!
nicohvi 2014年

10
我经常不喜欢“智能”的ruby代码,因为它需要一些时间才能知道它的实际作用。另一方面,您的解决方案很简单且具有描述性。
卢卡斯2014年

3
这确实应该是公认的答案!简单,干净,直接!
GigaBass 2015年

1
这个答案很优雅,但实际上并不能回答问题。该帖子指出需要替换的密钥是未知的...我们只知道它们以下划线开头,我们不知道密钥实际上是什么。
Dsel 2015年

2
因此,这将创建一个新的键/值对,您可以在其中指定新键并从hash.delete :old_key返回值中获取值,而删除操作将使用旧键。哇,我想在某处刺上纹身:-D谢谢
Bart C

136

rails Hash具有标准方法:

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

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

UPD:Ruby 2.5方法


4
这是Rails方法,不是标准方法。很好的答案。
user2422869

1
同样,此方法不能递归地使用哈希键。
塞尔吉奥·贝列夫斯基

5
deep_transform_keys可以用于它:) apidock.com/rails/v4.2.1/Hash/deep_transform_keys
gayavat 2015年

1
最后!这正是我搜索的内容!
TiSer

4
这是Ruby 2.5 以来
David Grayson

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 }

对于没有下划线前缀且没有进行额外修改的键应该没问题。


您的回答有效,但在病房后,我发现很少有这样的哈希
Manish Das

3
{“ _id” =>“ 4de7140772f8be03da000018”,“ _type” =>“ WorkStation”,“ created_at” =>“ 2011-06-02T10:24:35 + 05:45”,“ input_header_ids” => [],“ line_id “ =>” 4de7140472f8be03da000017“,” updated_at“ =>” 2011-06-02T10:24:35 + 05:45“}
Manish Das

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 Das

@Manish:我确实说过“如果所有键都是字符串,并且所有键都有下划线前缀”。我在更新中包括了用于“没有下划线前缀的键”的示例方法。
亩太短

2
@Manish:“ k”代表“键”,“ v”代表“值”,“ x”代表“我不知道该怎么称呼,但我受过数学训练,所以我称之为x”。
亩太短


11

如果要重命名哈希中的特定键,则可以执行以下操作:
假设我的哈希为 my_hash = {'test' => 'ruby hash demo'}
Now,现在我想将“ test”替换为“ message”,然后:
my_hash['message'] = my_hash.delete('test')


那么您的答案如何解决我的问题?如果您认为这有帮助,则可以在问题下的注释中添加。我的问题不是用另一个密钥替换一个密钥,您提供的解决方案是非常基本的Hash属性。就我而言,不是:hash[:new_key] = has[:old_key],而是:hash[:dynamic_key] = hash[:_dynamic_key],这是关于正则表达式的明确问题,而不是简单的哈希替换。
Manish Das 2013年

2
我通过谷歌搜索来到这里,想要@Swapnil的答案。谢谢
toobulkeh

10
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }

4
我喜欢您尝试使用正则表达式正确过滤掉下划线,但是您应该意识到,在ruby中,与javascript和其他代码不同,/ ^ /表示“字符串或行的开始”,而/ $ /表示“结束于”字符串OR LINE”。在这种情况下,密钥不太可能包含换行符,但是您应该意识到,在ruby中使用这两个运算符不仅容易出错,而且在对注入进行验证时使用错误时也很危险。请参阅此处以获取解释。希望您不介意传播这种意识。
Jorn van de Beek 2012年


1

我过度矫kill,提出了以下建议。我这样做的动机是附加到哈希键,以防止合并/拼合哈希时出现范围冲突。

例子

扩展哈希类

将密钥更新方法添加到哈希实例。

# 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

前置示例

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?!"}

展平和附加“范围”

如果您将哈希传递回给密钥,它将合并哈希,从而使集合变平。这使我们能够在平整哈希值时为键添加范围,以避免合并时覆盖键。

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"}
#   ]
# }

0

先前的答案足够好,但是它们可能会更新原始数据。如果您不希望原始数据受到影响,可以尝试使用我的代码。

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

首先,它将忽略键“ _id”,然后与更新的键合并。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.