Qual é a maneira (mais rápida / mais limpa / direta) de converter todas as chaves em um hash de strings para símbolos em Ruby?
Isso seria útil ao analisar o YAML.
my_hash = YAML.load_file('yml')
Eu gostaria de poder usar:
my_hash[:key]
Ao invés de:
my_hash['key']
hash.symbolize_keys
ehash.deep_symbolize_keys
faça o trabalho se estiver usando o Rails.Respostas:
Em Ruby> = 2.5 ( docs ), você pode usar:
Usando a versão mais antiga do Ruby? Aqui está uma linha que copiará o hash para uma nova com as teclas simbolizadas:
Com o Rails, você pode usar:
fonte
each_with_object
assim:my_hash.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
.tap
método para remover a necessidade de aprovaçãomemo
no final. Eu criei uma versão limpa de todas as soluções (também recursivas) gist.github.com/Integralist/9503099Aqui está um método melhor, se você estiver usando o Rails:
params. symbolize_keys
O fim.
Caso contrário, retire o código (também está no link):
fonte
symbolize_keys
o novo & working (Rails 3) URL. Inicialmente, corrigi o URLto_options
, mas não há documentação nesse link.symbolize_keys
na verdade tem uma descrição, então usei isso.hash.stringify_keys
funciona.Para o caso específico de YAML no Ruby, se as chaves começarem com '
:
', elas serão automaticamente internadas como símbolos.Resultado:
fonte
YAML#load_file
como padrão todas as chaves para símbolos em vez de cadeias sem ter que iniciar todas as chaves com dois pontos?Ainda mais conciso:
fonte
my_hash.map { |k, v| [k.to_sym, v] }.to_h
se você estiver usando o Rails, é muito mais simples - você pode usar um HashWithIndifferentAccess e acessar as teclas como String e como Symbols:
Veja também:
http://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html
Ou você pode usar a incrível "Facets of Ruby" Gem, que contém muitas extensões para as classes Ruby Core e Standard Library.
consulte também: http://rubyworks.github.io/rubyfaux/?doc=http://rubyworks.github.io/facets/docs/facets-2.9.3/core.json#api-class-Hash
fonte
Desde que
Ruby 2.5.0
você pode usarHash#transform_keys
ouHash#transform_keys!
.fonte
stringify_keys
orsymbolize_keys
.http://api.rubyonrails.org/classes/Hash.html#method-i-symbolize_keys
fonte
Aqui está uma maneira de simbolizar profundamente um objeto
fonte
Eu realmente gosto da gema Mash .
você pode fazer
mash['key']
, oumash[:key]
, oumash.key
fonte
Se você estiver usando json, e quiser usá-lo como um hash, no Core Ruby, poderá fazê-lo:
symbolize_names : se definido como true, retorna símbolos para os nomes (chaves) em um objeto JSON. Caso contrário, as strings serão retornadas. Strings são o padrão.
Doc: Json # parse symbolize_names
fonte
symbol_hash = JSON.parse(JSON.generate(YAML.safe_load(FILENAME)), symbolize_names: true)
é uma maneira bastante SECA (mas ineficiente) de obter rapidamente um hash com chaves aninhadas como símbolos se vier de um arquivo YAML.params.symbolize_keys
também irá funcionar. Esse método transforma chaves de hash em símbolos e retorna um novo hash.fonte
Uma modificação na resposta @igorsales
fonte
No Rails você pode usar:
Converte para:
fonte
deep_symbolize_keys
é adicionado na extensão Hash do Rails , mas não faz parte do núcleo do Ruby.Tantas respostas aqui, mas a função trilhos de um método é
hash.symbolize_keys
fonte
Este é o meu liner para hashes aninhados
fonte
Caso o motivo para você fazer isso seja porque seus dados originalmente vieram do JSON, você pode pular qualquer uma dessas análises apenas passando a
:symbolize_names
opção ao ingerir o JSON.Não é necessário Rails e funciona com Ruby> 1.9
fonte
Você pode ser preguiçoso e envolvê-lo em
lambda
:Mas isso funcionaria apenas para leitura do hash - não para escrita.
Para fazer isso, você pode usar
Hash#merge
O bloco init converterá as chaves uma vez sob demanda, embora, se você atualizar o valor da versão em cadeia da chave após acessar a versão do símbolo, a versão do símbolo não será atualizada.
Você também pode fazer com que o bloco init não atualize o hash, o que o protegerá desse tipo de erro, mas você ainda estará vulnerável ao contrário - a atualização da versão do símbolo não atualizará a versão da string:
Portanto, o que deve ser tomado com cuidado é alternar entre as duas formas principais. Ficar com um.
fonte
Algo como o seguinte funciona?
Ele copiará o hash, mas você não se importará com isso na maioria das vezes. Provavelmente existe uma maneira de fazer isso sem copiar todos os dados.
fonte
um fwiw de uma linha mais curto:
fonte
Que tal agora:
fonte
Isso é para pessoas que usam
mruby
e não têm nenhumsymbolize_keys
método definido:O método:
String
RuntimeError
fonte
!
nosymbolize_keys
. Caso contrário, funciona bem.A matriz que queremos mudar.
strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]
Crie uma nova variável como uma matriz vazia para que possamos "empurrar" os símbolos.
símbolos = []
Aqui é onde definimos um método com um bloco.
strings.each {| x | symbols.push (x.intern)}
Fim do código.
Portanto, essa é provavelmente a maneira mais direta de converter seqüências de caracteres em símbolos em seu array (s) em Ruby. Faça uma matriz de seqüências de caracteres, crie uma nova variável e defina a variável como uma matriz vazia. Em seguida, selecione cada elemento na primeira matriz que você criou com o método ".each". Em seguida, use um código de bloco para "empurrar" todos os elementos em sua nova matriz e use ".intern ou .to_sym" para converter todos os elementos em símbolos.
Os símbolos são mais rápidos porque economizam mais memória no seu código e você pode usá-los apenas uma vez. Os símbolos são mais comumente usados para chaves em hash, o que é ótimo. Eu não sou o melhor programador de ruby, mas esse tipo de código me ajudou muito. Se alguém souber uma maneira melhor, compartilhe e você também pode usar esse método para o hash!
fonte
Se você gostaria de uma solução de baunilha rubi e como eu não tenho acesso
ActiveSupport
aqui, é uma solução simbolizada profunda (muito semelhante às anteriores)fonte
A partir do Psych 3.0, você pode adicionar a opção symbolize_names:
Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
Nota: se você tiver uma versão Psych inferior a 3.0,
symbolize_names:
será ignorada silenciosamente.Meu Ubuntu 18.04 inclui-o imediatamente com o ruby 2.5.1p57
fonte
fonte
a
colocar colchetes para decompor o argumento do bloco para torná-lo ainda mais conciso. Veja minha resposta, por exemplo.Isso não é exatamente uma linha, mas transforma todas as chaves de seqüência de caracteres em símbolos, também os aninhados:
fonte
Eu gosto dessa linha única, quando não estou usando o Rails, porque não preciso fazer um segundo hash e reter dois conjuntos de dados enquanto o processo:
Hash # delete retorna o valor da chave excluída
fonte
O hash de facetas # deep_rekey também é uma boa opção, especialmente:
Amostra:
fonte
Em ruby, acho que essa é a maneira mais simples e fácil de entender de transformar chaves de string em hashes em símbolos:
Para cada chave no hash, chamamos delete, que o remove do hash (também delete retorna o valor associado à chave que foi excluída) e imediatamente o definimos como igual à chave simbolizada.
fonte
Semelhante às soluções anteriores, mas escrito de forma um pouco diferente.
O código não altera o hash passado.
fonte