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

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

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

我想让这个散列

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

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

129869 次浏览

你可以这样做

hash.inject({}){|option, (k,v) | option["id"] = v if k == "_id"; option}

这应该对你的情况有用!

如果所有的键都是字符串,并且都有下划线前缀,那么你可以用这个来修补哈希:

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 }

如果没有额外的修改,应该可以使用没有下划线前缀的键。

h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }
hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}
hash[:new_key] = hash.delete :old_key
如果我们想在哈希中重命名一个特定的键,那么我们可以这样做: 假设我的哈希值是 my_hash = {'test' => 'ruby hash demo'} 现在我想用'message'替换'test',然后:
my_hash['message'] = my_hash.delete('test') < / p >

rails哈希有标准的方法:

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

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

UPD: ruby 2.5方法

我费尽心思想出了下面这些。这背后的动机是附加到哈希键,以避免合并在一起/平坦哈希时范围冲突。

例子

扩展哈希类

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

扁平化和添加“范围”

如果你传递一个散列回rekey,它将合并散列,这允许你平展集合。这允许我们在扩展散列时为键添加作用域,以避免在合并时覆盖键。

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


前面的答案已经足够好了,但是它们可能会更新原始数据。 如果你不希望原始数据受到影响,你可以试试我的代码
 newhash=hash.reject{|k| k=='_id'}.merge({id:hash['_id']})

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

准确地回答了问题:

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

对于带有transform_keysdelete_prefix / delete_suffix方法的Ruby 2.5或更新版本:

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

如果你在一个哈希中有一个哈希,比如

hash = {
"object" => {
"_id"=>"4de7140772f8be03da000018"
}
}

如果你想将"_id"更改为类似__abc1的东西

你可以在这里使用deep_transform_keys并像这样做

hash.deep_transform_keys do |key|
key = "token" if key == "_id"
key
end

结果是

{
"object" => {
"token"=>"4de7140772f8be03da000018"
}
}

即使你有一个符号键哈希作为开始,比如

hash = {
object: {
id: "4de7140772f8be03da000018"
}
}

您可以组合所有这些概念,将它们转换为字符串键散列

hash.deep_transform_keys do |key|
key = "token" if key == :id
key.to_s
end

如果你只想改变一个键,在Ruby 2.8+中有一个简单的方法,使用transform_keys方法。在这个例子中,如果你想将_id改为id,那么你可以:

 hash.transform_keys({_id: :id})

参考:https://bugs.ruby-lang.org/issues/16274