Ruby-on-rails 如何用另一个键替换散列键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6210572/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 01:17:59  来源:igfitidea点击:

How to replace a hash key with another key

ruby-on-railsrubyruby-on-rails-3hash

提问by Manish Das

I have a condition where, I get a hash

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

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

and I want this hash as

我想要这个哈希作为

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

P.S: I don't know what are the keys in the hash, they are random which comes with an "_" prefix for every key and I want no underscores

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

回答by gayavat

hash[:new_key] = hash.delete :old_key

回答by gayavat

rails Hash has standard method for it:

rails Hash 有标准的方法:

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

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

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

UPD: ruby 2.5 method

UPD:ruby 2.5 方法

回答by mu is too short

If all the keys are strings and all of them have the underscore prefix, then you can patch up the hash in place with this:

如果所有键都是字符串并且所有键都有下划线前缀,那么您可以使用以下方法修补散列:

h.keys.each { |k| h[k[1, k.length - 1]] = h[k]; h.delete(k) }

The k[1, k.length - 1]bit grabs all of kexcept the first character. If you want a copy, then:

k[1, k.length - 1]位抓取k除第一个字符之外的所有内容。如果你想要一份副本,那么:

new_h = Hash[h.map { |k, v| [k[1, k.length - 1], v] }]

Or

或者

new_h = h.inject({ }) { |x, (k,v)| x[k[1, k.length - 1]] = v; x }

You could also use subif you don't like the k[]notation for extracting a substring:

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 }

And, if only some of the keys have the underscore prefix:

并且,如果只有一些键具有下划线前缀:

h.keys.each do |k|
  if(k[0,1] == '_')
    h[k[1, k.length - 1]] = h[k]
    h.delete(k)
  end
end

Similar modifications can be done to all the other variants above but these two:

可以对上述所有其他变体进行类似的修改,但这两个变体:

Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

should be okay with keys that don't have underscore prefixes without extra modifications.

没有下划线前缀的键应该没问题,无需额外修改。

回答by Sadiksha Gautam

you can do

你可以做

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

This should work for your case!

这应该适用于您的情况!

回答by Swapnil Chincholkar

If we want to rename a specific key in hash then we can do it as follows:
Suppose my hash is my_hash = {'test' => 'ruby hash demo'}
Now I want to replace 'test' by 'message', then:
my_hash['message'] = my_hash.delete('test')

如果我们想重命名散列中的特定键,那么我们可以按如下方式进行:
假设我的散列是my_hash = {'test' => 'ruby hash demo'}
现在我想用“消息”替换“测试”,那么:
my_hash['message'] = my_hash.delete('test')

回答by DigitalRoss

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

回答by maerics

hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}

回答by CTS_AE

I went overkill and came up with the following. My motivation behind this was to append to hash keys to avoid scope conflicts when merging together/flattening hashes.

我矫枉过正,想出了以下几点。我背后的动机是附加到散列键以避免合并/展平散列时的范围冲突。

Examples

例子

Extend Hash Class

扩展哈希类

Adds rekey method to Hash instances.

向 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

Prepend Example

前置示例

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

Trim Example

修剪示例

{ _id: 1, ___something_: 'what?!' }.rekey do |key|
  trimmed = key.to_s.tr('_', '')
  trimmed.to_sym
end
# => {:id=>1, :something=>"what?!"}

Flattening and Appending a "Scope"

展平和附加“范围”

If you pass a hash back to rekey it will merge the hash which allows you to flatten collections. This allows us to add scope to our keys when flattening a hash to avoid overwriting a key upon merging.

如果您将散列传回重新生成密钥,它将合并散列,从而使您可以展平集合。这允许我们在展平散列时为键添加范围以避免在合并时覆盖键。

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

回答by purushothaman poovai

Previous answers are good enough, but they might update original data. In case if you don't want the original data to be affected, you can try my code.

以前的答案已经足够好了,但它们可能会更新原始数据。如果你不希望原始数据受到影响,你可以试试我的代码。

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

First it will ignore the key '_id' then merge with the updated one.

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