web-dev-qa-db-ja.com

ハッシュキーを別のキーに置き換える方法

ハッシュを取得する条件があります

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

そして、私はこのハッシュが

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

P.S:ハッシュのキーが何なのかわかりません。それらはランダムであり、すべてのキーに「_」プレフィックスが付いており、アンダースコアは不要です

173
Manish Das

すべてのキーが文字列であり、すべてのキーにアンダースコアが付いている場合、これでハッシュを修正できます:

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

上記の他のすべてのバリアントに対して同様の変更を行うことができますが、次の2つです。

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

アンダースコアプレフィックスを持たないキーについては、追加の変更なしで問題ありません。

38
mu is too short
hash[:new_key] = hash.delete :old_key
657
gayavat

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メソッド

125
gayavat

できるよ

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

これはあなたのケースで動作するはずです!

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

ハッシュ内の特定のキーの名前を変更する場合は、次のようにします。
私のハッシュがmy_hash = {'test' => 'Ruby hash demo'}であるとします
次に、「テスト」を「メッセージ」に置き換えます。
my_hash['message'] = my_hash.delete('test')

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

私は行き過ぎて、以下を思いついた。この背後にある私の動機は、ハッシュをマージ/フラット化するときにスコープの競合を避けるためにハッシュキーに追加することでした。

ハッシュクラスの拡張

キー再生成メソッドをハッシュインスタンスに追加します。

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

1
CTS_AE