Rubyでハッシュ内のすべてのキーを文字列からシンボルに変換する(最速/クリーン/簡単)方法は何ですか?
これはYAMLを解析するときに便利です。
my_hash = YAML.load_file('yml')
使用できるようにしたい:
my_hash[:key]
のではなく:
my_hash['key']
hash.symbolize_keys
hash.deep_symbolize_keys
Railsを使用している場合は、この作業を行います。
Rubyでハッシュ内のすべてのキーを文字列からシンボルに変換する(最速/クリーン/簡単)方法は何ですか?
これはYAMLを解析するときに便利です。
my_hash = YAML.load_file('yml')
使用できるようにしたい:
my_hash[:key]
のではなく:
my_hash['key']
hash.symbolize_keys
hash.deep_symbolize_keys
Railsを使用している場合は、この作業を行います。
回答:
ではルビー> = 2.5(ドキュメント)あなたが使用することができます。
my_hash.transform_keys(&:to_sym)
古いRubyバージョンを使用していますか?以下は、ハッシュを新しいキーに記号化されたキーでコピーするワンライナーです。
my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
Railsのあなたは使用することができます。
my_hash.symbolize_keys
my_hash.deep_symbolize_keys
each_with_object
ように使用できます:my_hash.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
.tap
メソッドを使用memo
して、最後に渡す必要を取り除くこともできます。私はすべてのソリューション(再帰的なソリューションも含む)のクリーンアップバージョンを作成しましたgist.github.com/Integralist/9503099
Railsを使用している場合は、より良い方法を次に示します。
パラメータ。symbolize_keys
終わり。
そうでない場合は、コードを削除してください(リンクにも含まれています)。
myhash.keys.each do |key|
myhash[(key.to_sym rescue key) || key] = myhash.delete(key)
end
symbolize_keys
新しい&機能している(Rails 3)URL に切り替えました。元々はのURLを修正しただけですがto_options
、そのリンクにはドキュメントがありません。symbolize_keys
実際に説明があるので、代わりにそれを使用しました。
hash.stringify_keys
動作します。
RubyのYAMLの特定のケースでは、キーが「:
」で始まる場合、それらは自動的にシンボルとしてインターンされます。
「yaml」が必要 「pp」が必要 yaml_str = " 接続: -ホスト:host1.example.com ポート:10000 -ホスト:host2.example.com ポート:20000 」 yaml_sym = " :接続: -:host:host1.example.com :ポート:10000 -:host:host2.example.com :ポート:20000 」 pp yaml_str = YAML.load(yaml_str) yaml_str.keys.first.classを置く pp yaml_sym = YAML.load(yaml_sym) yaml_sym.keys.first.classを置く
出力:
#/opt/ruby-1.8.6-p287/bin/ruby〜/ test.rb {"接続" => [{"ポート" => 10000、 "ホスト" => "host1.example.com"}、 {"ポート" => 20000、 "ホスト" => "ホスト2.example.com"}]} ストリング {:接続=> [{:port => 10000、:host => "host1.example.com"}、 {:port => 20000、:host => "host2.example.com"}]} シンボル
YAML#load_file
すべてのキーをコロンで始める必要がない文字列ではなく、すべてのキーをデフォルトでシンボルに設定する方法はありますか?
さらに簡潔:
Hash[my_hash.map{|(k,v)| [k.to_sym,v]}]
my_hash.map { |k, v| [k.to_sym, v] }.to_h
Railsを使用している場合は、はるかに簡単です。HashWithIndifferentAccessを使用して、文字列と記号の両方としてキーにアクセスできます。
my_hash.with_indifferent_access
も参照してください:
http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html
または、Rubyコアおよび標準ライブラリクラスへの多くの拡張機能が含まれている素晴らしい "Rubyのファセット" Gemを使用できます。
require 'facets'
> {'some' => 'thing', 'foo' => 'bar'}.symbolize_keys
=> {:some=>"thing", :foo=>"bar}
参照:http : //rubyworks.github.io/rubyfaux/?doc=http : //rubyworks.github.io/facets/docs/facets-2.9.3/core.json#api-class-Hash
またはRuby 2.5.0
を使用できるので。Hash#transform_keys
Hash#transform_keys!
{'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
stringify_keys
またはのように値を変更するための同等の方法がないように見えるので、それは本当に素晴らしいですsymbolize_keys
。
http://api.rubyonrails.org/classes/Hash.html#method-i-symbolize_keys
hash = { 'name' => 'Rob', 'age' => '28' }
hash.symbolize_keys
# => { name: "Rob", age: "28" }
私はマッシュの宝石が本当に好きです。
あなたがすることができますmash['key']
、またはmash[:key]
、またはmash.key
jsonを使用していて、それをハッシュとして使用したい場合は、コアRubyで実行できます。
json_obj = JSON.parse(json_str, symbolize_names: true)
symbolize_names:trueに設定すると、JSONオブジェクトで名前(キー)のシンボルを返します。それ以外の場合、文字列が返されます。文字列がデフォルトです。
symbol_hash = JSON.parse(JSON.generate(YAML.safe_load(FILENAME)), symbolize_names: true)
YAMLファイルから取得した場合に、ネストされたキーを記号として持つハッシュをすばやく取得するためのかなりDRY(ただし非効率的な)方法です。
params.symbolize_keys
も動作します。このメソッドは、ハッシュキーをシンボルに変換し、新しいハッシュを返します。
@igorsales回答の変更
class Object
def deep_symbolize_keys
return self.inject({}){|memo,(k,v)| memo[k.to_sym] = v.deep_symbolize_keys; memo} if self.is_a? Hash
return self.inject([]){|memo,v | memo << v.deep_symbolize_keys; memo} if self.is_a? Array
return self
end
end
Railsで使用できるもの:
{'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys!
変換:
{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}}
deep_symbolize_keys
はRailsのハッシュ拡張に追加されていますが、Rubyコアの一部ではありません。
ここには非常に多くの答えがありますが、1つのメソッドrails関数は hash.symbolize_keys
あなたは怠惰で、それをaにラップすることができますlambda
:
my_hash = YAML.load_file('yml')
my_lamb = lambda { |key| my_hash[key.to_s] }
my_lamb[:a] == my_hash['a'] #=> true
ただし、これはハッシュから読み取る場合にのみ機能し、書き込みでは機能しません。
それを行うには、 Hash#merge
my_hash = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(YAML.load_file('yml'))
initブロックは、オンデマンドでキーを1回変換しますが、シンボルバージョンにアクセスした後にキーの文字列バージョンの値を更新した場合、シンボルバージョンは更新されません。
irb> x = { 'a' => 1, 'b' => 2 }
#=> {"a"=>1, "b"=>2}
irb> y = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(x)
#=> {"a"=>1, "b"=>2}
irb> y[:a] # the key :a doesn't exist for y, so the init block is called
#=> 1
irb> y
#=> {"a"=>1, :a=>1, "b"=>2}
irb> y[:a] # the key :a now exists for y, so the init block is isn't called
#=> 1
irb> y['a'] = 3
#=> 3
irb> y
#=> {"a"=>3, :a=>1, "b"=>2}
また、initブロックでハッシュを更新しないようにすることもできます。これにより、この種のエラーから保護されますが、逆の脆弱性は依然として存在します。シンボルバージョンを更新しても、文字列バージョンは更新されません。
irb> q = { 'c' => 4, 'd' => 5 }
#=> {"c"=>4, "d"=>5}
irb> r = Hash.new { |h,k| h[k.to_s] }.merge(q)
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called
#=> 4
irb> r
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called again, since this key still isn't in r
#=> 4
irb> r[:c] = 7
#=> 7
irb> r
#=> {:c=>7, "c"=>4, "d"=>5}
したがって、これらについて注意すべきことは、2つの主要な形式を切り替えることです。1つに固執します。
次のようなものでしょうか?
new_hash = Hash.new
my_hash.each { |k, v| new_hash[k.to_sym] = v }
ハッシュをコピーしますが、ほとんどの場合、そのことは気にしません。すべてのデータをコピーせずにそれを行う方法がおそらくあります。
これはどう:
my_hash = HashWithIndifferentAccess.new(YAML.load_file('yml'))
# my_hash['key'] => "val"
# my_hash[:key] => "val"
これは、メソッドを定義しmruby
ていないユーザーを対象としていますsymbolize_keys
。
class Hash
def symbolize_keys!
self.keys.each do |k|
if self[k].is_a? Hash
self[k].symbolize_keys!
end
if k.is_a? String
raise RuntimeError, "Symbolizing key '#{k}' means overwrite some data (key :#{k} exists)" if self[k.to_sym]
self[k.to_sym] = self[k]
self.delete(k)
end
end
return self
end
end
メソッド:
String
RuntimeError
!
in を忘れましたsymbolize_keys
。それ以外の場合は正常に動作します。
strings = ["HTML"、 "CSS"、 "JavaScript"、 "Python"、 "Ruby"]
記号= []
strings.each {| x | symbols.push(x.intern)}
したがって、これはおそらくRubyで文字列を配列内のシンボルに変換する最も簡単な方法です。文字列の配列を作成し、新しい変数を作成して、変数を空の配列に設定します。次に、「。each」メソッドで作成した最初の配列の各要素を選択します。次に、ブロックコードを使用して新しい配列のすべての要素を「.push」し、「。internまたは.to_sym」を使用してすべての要素をシンボルに変換します。
シンボルはコード内のメモリを節約し、一度しか使用できないため、より高速です。記号は、ハッシュのキーに最もよく使用されます。私はルビーのプログラマーとしては最高ではありませんが、この形式のコードはとても役に立ちました。誰かがより良い方法を知っている場合は、共有してください。ハッシュにもこの方法を使用できます。
あなたがバニラルビーソリューションを望んでいて、私がActiveSupport
ここにアクセスできない場合は、深い象徴的なソリューションです(以前のものと非常に似ています)
def deep_convert(element)
return element.collect { |e| deep_convert(e) } if element.is_a?(Array)
return element.inject({}) { |sh,(k,v)| sh[k.to_sym] = deep_convert(v); sh } if element.is_a?(Hash)
element
end
Psych 3.0 以降では、symbolize_names :オプションを追加できます
Psych.load("---\n foo: bar")
# => {"foo"=>"bar"}
Psych.load("---\n foo: bar", symbolize_names: true)
# => {:foo=>"bar"}
注:Psychのバージョンが3.0より低い場合、symbolize_names:
警告なしで無視されます。
私のUbuntu 18.04には、Ruby 2.5.1p57に標準で含まれています
ruby-1.9.2-p180 :001 > h = {'aaa' => 1, 'bbb' => 2}
=> {"aaa"=>1, "bbb"=>2}
ruby-1.9.2-p180 :002 > Hash[h.map{|a| [a.first.to_sym, a.last]}]
=> {:aaa=>1, :bbb=>2}
a
大括弧で囲んでブロック引数を分解すると、これをさらに簡潔にすることができます。例えば私の答えを見てください。
これは厳密には1行ではありませんが、すべての文字列キーをシンボルに変換します。
def recursive_symbolize_keys(my_hash)
case my_hash
when Hash
Hash[
my_hash.map do |key, value|
[ key.respond_to?(:to_sym) ? key.to_sym : key, recursive_symbolize_keys(value) ]
end
]
when Enumerable
my_hash.map { |value| recursive_symbolize_keys(value) }
else
my_hash
end
end
ファセットのHash#deep_rekeyも良いオプションです、特に:
サンプル:
require 'facets/hash/deep_rekey'
my_hash = YAML.load_file('yml').deep_rekey
Rubyでは、これがハッシュ内の文字列キーをシンボルに変換する最も単純で理解しやすい方法であることがわかります。
my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key)}
ハッシュ内の各キーについて、それを削除し、ハッシュから削除します(また、delete は削除されたキーに関連付けられた値を返します)。これをすぐに記号化されたキーと等しく設定します。
以前のソリューションに似ていますが、少し異なって書かれています。
コードは渡されたハッシュを変更しません。
module HashUtils
def symbolize_keys(hash)
transformer_function = ->(key) { key.to_sym }
transform_keys(hash, transformer_function)
end
def stringify_keys(hash)
transformer_function = ->(key) { key.to_s }
transform_keys(hash, transformer_function)
end
def transform_keys(obj, transformer_function)
case obj
when Array
obj.map{|value| transform_keys(value, transformer_function)}
when Hash
obj.each_with_object({}) do |(key, value), hash|
hash[transformer_function.call(key)] = transform_keys(value, transformer_function)
end
else
obj
end
end
end