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


191

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

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

そして私はこのハッシュを

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

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


これはあなたを助けるかもしれない:stackoverflow.com/questions/4044451/...
腐食

+1役立つ質問
ashisrai_ 2013年

@ a5his:お役に立ててうれしいです:)
Manish Das

回答:


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

8
いくつかのLOCを保存しました。
nicohvi 2014年

10
実際に何をしているのかを伝えるのに時間がかかるので、「スマートな」ルビコードを好まないことがよくあります。一方、ソリューションはシンプルで説明的です。
Lucas

3
これは確かに受け入れられる答えになるはずです!簡単、きれい、そして真っ直ぐです!
GigaBass 2015

1
この答えはエレガントですが、実際には質問の答えにはなりません。投稿には、置換が必要なキーは不明であると記載されています...それらがアンダースコアで始まることがわかっているだけで、キーが実際には何であるかわかりません。
Dsel、2015

2
これにより、新しいキーと値のペアが作成され、新しいキーを指定して、hash.delete :old_key返される値から値を取得し、削除では古いキーを使用します。うわー、私はそれがどこかに入れ墨をしたいです:-Dありがとう
バート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
また、このメソッドはハッシュキーを再帰的に操作することはできません。
Sergio Belevskij 2015年

5
deep_transform_keysを使用できます:) apidock.com/rails/v4.2.1/Hash/deep_transform_keys
gayavat

1
やっと!これはまさに私が検索したものです!
TiSer

4
これは、Ruby 2.5の時点での言語の標準部分です:docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys
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 }

あなたも使うことができます subk[]部分文字列を抽出するための表記法が気に入らない場合にできます。

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 }

追加の変更を行わずにアンダースコアのプレフィックスを持たないキーでも問題ありません。


あなたの答えはうまくいきましたが、区の後、私はこのようなハッシュをいくつか見つけました
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

@マニッシュ:「すべてのキーが文字列で、すべてにアンダースコアのプレフィックスが付いている場合」と言いました。「アンダースコアプレフィックスのないキー」のアプローチ例をアップデートに含めました。
muが短すぎる

2
@マニッシュ:「k」は「キー」、「v」は「値」、「x」は「何と呼ぶか​​わからないが、数学者として訓練を受けたのでxと呼ぶ」
muが短すぎる


11

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


あなたの答えは私の問題の解決策ですか?これが役に立ったと思われる場合は、質問の下のコメントに追加できます。私の質問は、キーを別のキーに置き換えることではありませんでした。あなたが与えた解決策は、非常に基本的なハッシュプロパティです。私の場合、それは:hash[:new_key] = has[:old_key]ではなく、代わりに:ですhash[:dynamic_key] = hash[:_dynamic_key]。これは、単純なハッシュ置換ではなく、正規表現に関する明確な質問でした。
Manish Das

2
私はグーグル検索でこれに来て、@ Swapnilの答えが欲しかった。ありがとう
toobulkeh

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

4
下線を適切に除外するために正規表現を使用しようとしたのが好きですが、Rubyでは、javascriptなどとは異なり、/ ^ /は「文字列または行の始まり」を意味し、/ $ /は「終わり」を意味することに注意してください。文字列OR LINE '。この場合、キーに改行が含まれている可能性は低いですが、ルビでこれらの2つの演算子を使用すると、エラーが発生しやすくなるだけでなく、注入に対する検証で誤って使用すると非常に危険になることにも注意してください。説明はこちらをご覧ください。あなたが意識を広めることを気にしないことを願っています。
Jorn van de Beek


1

私はやりすぎになり、次のことを思いつきました。これの背後にある私の動機は、ハッシュキーに追加して、一緒にマージ/ハッシュをフラット化するときにスコープの競合を回避することでした。

ハッシュクラスの拡張

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

# 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」を無視して、更新されたキーとマージします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.