如何用另一个键替换散列键
Posted
技术标签:
【中文标题】如何用另一个键替换散列键【英文标题】:How to replace a hash key with another key 【发布时间】:2011-09-06 19:45:25 【问题描述】:我有一个条件,我得到一个哈希
hash = "_id"=>"4de7140772f8be03da000018", .....
我希望这个哈希为
hash = "id"=>"4de7140772f8be03da000018", ......
P.S:我不知道哈希中的键是什么,它们是随机的,每个键都有一个“_”前缀,我不想要下划线
【问题讨论】:
这可能对你有帮助:***.com/questions/4044451/… +1 有用的问题 @a5his : 我很高兴能帮上忙 :) 相关:How to rename the_id
keys to id
in an array of MongoDB documents
【参考方案1】:
hash[:new_key] = hash.delete :old_key
【讨论】:
救了我几个 LOC,爱它! 我经常不喜欢“智能”的 ruby 代码,因为它需要一些时间来判断它到底在做什么。另一方面,您的解决方案简单且具有描述性。 这确实应该是公认的答案!简单、干净、直截了当! 这个答案很优雅,但实际上并没有回答问题。该帖子指出需要替换的键是未知的......我们只知道它们以下划线开头,我们不知道键实际上是什么。 所以这会创建一个新的键/值对,您可以在其中指定新键并从hash.delete :old_key
返回的值中获取值,并且删除使用旧键。哇,我想把它纹在某个地方:-D 谢谢【参考方案2】:
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 方法
【讨论】:
这是 Rails 方法,不是标准的。不过答案很好。 另外,这个方法不能递归操作哈希键。 deep_transform_keys 可以用它:) apidock.com/rails/v4.2.1/Hash/deep_transform_keys 终于!这正是我搜索的内容! 这是 Ruby 2.5 语言的标准部分:docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys【参考方案3】:如果所有的键都是字符串并且它们都有下划线前缀,那么你可以用这个来修补散列:
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
如果您不喜欢 k[]
表示法来提取子字符串,您也可以使用 sub
:
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
对于没有下划线前缀且无需额外修改的键应该没问题。
【讨论】:
你的答案有效,但在病房后我发现很少有这样的哈希 "_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" "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:我确实说过“如果所有键都是字符串并且它们都具有下划线前缀”。我在更新中为您的“没有下划线前缀的键”提供了一个示例方法。 @Manish:“k”代表“key”,“v”代表“value”,“x”代表“我不知道该怎么称呼它,但我被训练为数学家所以我称之为 x"。【参考方案4】:你可以的
hash.inject()|option, (k,v) | option["id"] = v if k == "_id"; option
这应该适用于您的情况!
【讨论】:
【参考方案5】:如果我们想重命名哈希中的特定键,那么我们可以这样做:
假设我的哈希是 my_hash = 'test' => 'ruby hash demo'
现在我想用“消息”替换“测试”,然后: my_hash['message'] = my_hash.delete('test')
【讨论】:
您的答案如何解决我的问题?如果您认为这很有帮助,那么您可以在问题下方的评论中添加。我的问题不是用另一个键替换一个键,你给出的解决方案是非常基本的 Hash 属性。就我而言,它不是:hash[:new_key] = has[:old_key]
,而是:hash[:dynamic_key] = hash[:_dynamic_key]
,这是关于正则表达式的明确问题,而不是简单的哈希替换。
我通过谷歌搜索找到了这个并想要@Swapnil 的答案。谢谢【参考方案6】:
h.inject() |m, (k,v)| m[k.sub(/^_/,'')] = v; m
【讨论】:
我喜欢你尝试使用正则表达式来正确过滤下划线,但你应该知道,在 ruby 中,与 javascript 和其他人不同,/^/ 表示“字符串或行的开头”,和 /$/ 表示“字符串结束或行”。在这种情况下,键中不太可能有换行符,但您应该知道,在 ruby 中使用这两个运算符不仅容易出错,而且在针对注入的验证中使用错误时也非常危险。有关说明,请参阅 here。希望您不介意传播这种意识。【参考方案7】:对于 Ruby 2.5 或更高版本的 transform_keys 和 delete_prefix / delete_suffix 方法:
hash1 = '_id' => 'random1'
hash2 = 'old_first' => '123456', 'old_second' => '234567'
hash3 = 'first_com' => 'google.com', 'second_com' => 'amazon.com'
hash1.transform_keys |key| key.delete_prefix('_')
# => "id"=>"random1"
hash2.transform_keys |key| key.delete_prefix('old_')
# => "first"=>"123456", "second"=>"234567"
hash3.transform_keys |key| key.delete_suffix('_com')
# => "first"=>"google.com", "second"=>"amazon.com"
【讨论】:
非常感谢!【参考方案8】:hash.each |k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'
【讨论】:
【参考方案9】:我有点矫枉过正,想出了以下内容。我这样做的动机是在合并/展平哈希时附加到哈希键以避免范围冲突。
示例
扩展哈希类
为 Hash 实例添加 rekey 方法。
# 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"
# ]
#
【讨论】:
【参考方案10】:以前的答案已经足够好,但它们可能会更新原始数据。 如果你不希望原始数据受到影响,你可以试试我的代码。
newhash=hash.reject|k| k=='_id'.merge(id:hash['_id'])
首先它将忽略键“_id”,然后与更新的键合并。
【讨论】:
【参考方案11】:准确回答问题:
hash = "_id"=>"4de7140772f8be03da000018"
hash.transform_keys |key| key[1..]
# => "id"=>"4de7140772f8be03da000018"
方法 transform_keys
自 Ruby 2.5 版本开始存在于 Hash 类中。
https://blog.bigbinary.com/2018/01/09/ruby-2-5-adds-hash-transform_keys-method.html
【讨论】:
以上是关于如何用另一个键替换散列键的主要内容,如果未能解决你的问题,请参考以下文章