해시에서 문자열을 기호로 변환하는 가장 좋은 방법
Ruby에서 해시의 모든 키를 문자열에서 기호로 변환하는 가장 빠른(가장 빠른/가장 깨끗한/직접적인) 방법은 무엇입니까?
이것은 YAML을 구문 분석할 때 유용합니다.
my_hash = YAML.load_file('yml')
다음과 같은 기능을 사용할 수:
my_hash[:key]
다음보다는:
my_hash['key']
Ruby >= 2.5(아래)에서 다음을 사용할 수 있습니다.
my_hash.transform_keys(&:to_sym)
이전 버전의 루비를 사용하시겠습니까?다음은 키가 기호화된 해시를 새 해시에 복사하는 한 줄기입니다.
my_hash = my_hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
레일을 사용하면 다음을 사용할 수 있습니다.
my_hash.symbolize_keys
my_hash.deep_symbolize_keys
레일즈를 사용하는 경우 더 좋은 방법은 다음과 같습니다.
params.sys_key
끝.
그렇지 않은 경우 코드를 복사합니다(링크에도 있음).
myhash.keys.each do |key|
myhash[(key.to_sym rescue key) || key] = myhash.delete(key)
end
, 가 'Ruby 에YAML의'로 ,:
그들은 자동적으로 상징으로 수용될 것입니다.
'sl'이 필요합니다.'pp'가 필요합니다.yaml_str = "연결: 호스트: host1.example.com포트: 10000호스트: host2.example.com포트: 20000"yaml_sym = ":연결: :호스트: host1.example.com:포트: 10000:호스트: 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/message-1.8.6-p287/bin/message ~/test.message{"연결"=>[{"port"=>10000, "host"=>"host1.example.com ",{"port"=>20000, "host"=>"host2.example.com "}}끈{:연결=>[{:port=>10000, :host=>"host1.example.com ",{:port=>20000, :host=>"host2.example.com "}}기호.
Rails를 사용하는 경우 훨씬 더 간단합니다. HashWithIndifferent Access를 사용하여 String 및 Symbolic으로 키에 액세스할 수 있습니다.
my_hash.with_indifferent_access
참고 항목:
http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html
또는 Ruby Core 및 Standard Library 클래스에 대한 많은 확장이 포함된 멋진 "Ruby Facets" 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
훨씬 더 간결함:
Hash[my_hash.map{|(k,v)| [k.to_sym,v]}]
때부터Ruby 2.5.0
또는 를 사용할 수 있습니다.
{'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
http://api.rubyonrails.org/classes/Hash.html#method-i-symbolize_keys
hash = { 'name' => 'Rob', 'age' => '28' }
hash.symbolize_keys
# => { name: "Rob", age: "28" }
만약 당신이 json을 사용하고 있고 그것을 해시로 사용하고 싶다면, 코어 Ruby에서 당신은 그것을 할 수 있습니다:
json_obj = JSON.parse(json_str, symbolize_names: true)
symbol_names:true로 설정하면 JSON 개체의 이름(키)에 대한 기호를 반환합니다.그렇지 않으면 문자열이 반환됩니다.문자열이 기본값입니다.
물체를 깊이 상징하는 방법은 다음과 같습니다.
def symbolize(obj)
return obj.inject({}){|memo,(k,v)| memo[k.to_sym] = symbolize(v); memo} if obj.is_a? Hash
return obj.inject([]){|memo,v | memo << symbolize(v); memo} if obj.is_a? Array
return obj
end
저는 매쉬 보석을 정말 좋아합니다.
할수있습니다mash['key']
또는mash[:key]
또는mash.key
@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
params.symbolize_keys
또한 작동할 것입니다.이 메서드는 해시 키를 기호로 변환하고 새 해시를 반환합니다.
레일에서 다음을 사용할 수 있습니다.
{'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys!
변환 대상:
{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}}
, 한은 레일즈 입니다.hash.symbolize_keys
이것은 중첩된 해시를 위한 나의 유일한 라이너입니다.
def symbolize_keys(hash)
hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v }
end
데이터가 원래 JSON에서 가져온 것이기 때문에 이 작업을 수행해야 하는 경우, 데이터를 전달하기만 하면 이 구문 분석을 건너뛸 수 있습니다.:symbolize_names
JSON을 섭취할 때의 옵션.
레일이 필요하지 않으며 1.9 이상의 Ruby와 함께 작동합니다.
JSON.parse(my_json, :symbolize_names => true)
귀찮을 수도 있고, 그것을 포장할 수도 있습니다.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 블록은 요청 시 키를 한 번 변환하지만 기호 버전에 액세스한 후 키의 문자열 버전 값을 업데이트하면 기호 버전이 업데이트되지 않습니다.
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}
그래서 이것들에 주의해야 할 것은 두 가지 주요 형태 사이를 전환하는 것입니다.하나만.
다음과 같은 것이 가능할까요?
new_hash = Hash.new
my_hash.each { |k, v| new_hash[k.to_sym] = v }
해시를 복사하겠지만 대부분의 경우에는 신경 쓰지 않을 것입니다.모든 데이터를 복사하지 않고 수행할 수 있는 방법이 있을 것입니다.
더 짧은 1-라이너 fwi:
my_hash.inject({}){|h,(k,v)| h.merge({ 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
방법:
- 는 다음키나타니다냅만▁다▁are니▁keys나타인 키만 .
String
- 해시의 ).
RuntimeError
- 기호는 또한 재귀적으로 포함된 해시를 나타냅니다.
- 기호화된 해시 반환
- 제자리에서 작동합니다!
변경할 배열입니다.
문자열 = ["HTML", "CSS", "자바스크립트", "파이썬", "루비"]
새 변수를 빈 배열로 만들어 기호를 ".push in"할 수 있도록 합니다.
기호 = [ ]
여기서 블록을 사용하여 메서드를 정의합니다.
strings.각 {|x| 기호.sigmes(x.intern)}
코드 끝.
따라서 이것이 루비에서 문자열을 배열의 기호로 변환하는 가장 간단한 방법일 것입니다.문자열 배열을 만든 다음 새 변수를 만들고 변수를 빈 배열로 설정합니다.그런 다음 ".각" 방법으로 만든 첫 번째 배열에서 각 요소를 선택합니다.그런 다음 블록 코드를 사용하여 새 배열의 모든 요소를 ".push"하고 ".inter" 또는 .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부터는 symbol_names: 옵션을 추가할 수 있습니다.
Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
참고: 3.0보다 낮은 Psych 버전이 있는 경우symbolize_names:
자동으로 무시됩니다.
내 Ubuntu 18.04는 루비 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}
이것은 정확히 한 줄로 된 것은 아니지만 모든 문자열 키를 기호로 변환하고 중첩된 키도 표시합니다.
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
Rails를 사용하지 않을 때는 이 한 줄기가 좋습니다. 두 번째 해시를 만들고 데이터를 처리하는 동안 두 세트를 보관할 필요가 없기 때문입니다.
my_hash = { "a" => 1, "b" => "string", "c" => true }
my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key) }
my_hash
=> {:a=>1, :b=>"string", :c=>true}
Hash#delete는 삭제된 키의 값을 반환합니다.
Facets의 Hash#deep_rekey도 좋은 옵션입니다. 특히 다음과 같습니다.
- 만약 당신이 당신의 프로젝트에서 다른 면들로부터 다른 설탕의 사용을 발견한다면,
- 암호화된 한 줄기보다 코드 가독성을 선호하는 경우.
샘플:
require 'facets/hash/deep_rekey'
my_hash = YAML.load_file('yml').deep_rekey
루비에서 나는 이것이 해시의 문자열 키를 기호로 바꾸는 가장 간단하고 이해하기 쉬운 방법이라고 생각합니다.
my_hash.keys.each { |key| my_hash[key.to_sym] = my_hash.delete(key)}
해시의 각 키에 대해 해시에서 제거하는 삭제를 호출하고(삭제된 키와 관련된 값도 반환함), 즉시 기호화된 키와 동일하게 설정합니다.
이전 솔루션과 비슷하지만 약간 다르게 작성되었습니다.
- 이렇게 하면 중첩되거나 배열이 있는 해시를 사용할 수 있습니다.
- 키를 문자열로 변환하는 것을 보너스로 받습니다.
코드가 전달된 해시를 변환하지 않습니다.
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
언급URL : https://stackoverflow.com/questions/800122/best-way-to-convert-strings-to-symbols-in-hash
'source' 카테고리의 다른 글
CASE 문과 DECODE가 동일합니까? (0) | 2023.06.28 |
---|---|
Oracle이 모든 테이블의 통계를 수동으로 업데이트 (0) | 2023.06.28 |
돌연변이 및 동작을 통한 Vuex 빅 어레이 처리 (0) | 2023.06.28 |
MongoEngine을 사용하여 정렬하시겠습니까? (0) | 2023.06.28 |
Dapper를 사용하여 한 번의 왕복에 여러 개의 SQL 문이 있습니다.그물 (0) | 2023.06.28 |