Não tenho certeza de que haja muita vantagem em classificar um hash, a menos que você esteja usando eachou each_pairiterar sobre ele. Mesmo assim, eu provavelmente ainda pegaria as chaves, classificá-las e iterar sobre elas, pegando os valores conforme necessário. Isso garante que o código se comporte corretamente nos Rubies mais antigos.
the Tin Man
Também faz sentido no ruby 1.9. Eu tinha uma coleção de compromissos agrupados por datas (como chaves) provenientes do db e eu classificava manualmente através do ruby. Por exemplo. {"2012-09-22": [...], "2012-09-30": [...], "12/10/2012": [...]}
Adit Saxena
Sim, acho que seu processo Hash [h.sort] é mais eficaz do que as chaves de classificação e, em seguida, acesso novamente o hash através das chaves classificadas.
@zachaysan mas ela não funciona: h.sort{|a,z|a<=>z}.to_h(testado 2.1.10, 2.3.3)
whitehat101
@ whitehat101 Você está certo. Eu tive um bug ( aé uma matriz, não apenas a chave). Eu apaguei meu comentário.
Zachaysan
Apenas no caso de alguém está procurando uma maneira de classificar uma matriz de hashes, isso vai fazer o truque (onde h é a matriz): h.map(&:sort).map(&:to_h).
JM Janzen
82
Nota: Ruby> = 1.9.2 possui um hash de preservação de ordem: as chaves de pedido são inseridas e serão as que estão enumeradas. O abaixo se aplica a versões mais antigas ou a códigos compatíveis com versões anteriores.
Não há conceito de um hash classificado. Então não, o que você está fazendo não está certo.
Se você deseja classificá-lo para exibição, retorne uma string:
h.sort.map do|key,value|# keys will arrive in order to this block, with their associated value.end
mas, em resumo, não faz sentido falar sobre um hash classificado. Nos documentos , "A ordem na qual você percorre um hash por chave ou valor pode parecer arbitrária e geralmente não estará na ordem de inserção". Portanto, inserir chaves em uma ordem específica no hash não ajudará.
"A partir do 1.9.2, a ordem de inserção de hash será preservada.", E é agradável.
the Tin Man
2
Sobre o meu primeiro comentário (sentindo-me engraçado): Por exemplo, confiar na ordenação de hash seria silencioso e imprevisível para versões do Ruby anteriores à 1.9.2.
quer
5
Como essa resposta obteve cerca de 20 + 1s sem responder a nenhuma das duas partes da pergunta do OP? "1) Essa (exemplo do OP) seria a melhor maneira de classificar um hash, 2) e retornar o objeto Hash"? Eu não invejo + 1s :) é só depois dessa leitura que eu ainda fico com as perguntas originais. Além disso, se o ponto é que não existe um hash classificado, observe os comentários para a resposta escolhida para esta pergunta stackoverflow.com/questions/489139/…
jj_
64
Eu sempre usei sort_by. Você precisa agrupar a #sort_bysaída Hash[]para gerar um hash, caso contrário, ela gera uma matriz de matrizes. Como alternativa, para fazer isso, você pode executar o #to_hmétodo na matriz de tuplas para convertê-las em uma k=>vestrutura (hash).
usar sort_byum hash retornará uma matriz. Você precisaria mapeá-lo como um hash novamente. Hash[hsh.sort_by{|k,v| v}]
stevenspiel
1
sim, os interpreta classe enumerador hashes como matrizes eu acho
boulder_ruby
3
Direita, classificar é em valores: hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}.
Cary Swoveland
1
Observe que as chamadas to_hsão suportadas apenas no Ruby 2.1.0+
Phrogz
1
há um erro de digitação no comentário, correção:sort_by{|k,v| v}.to_h)
jitter
13
Não, não é (Ruby 1.9.x)
require 'benchmark'
h ={"a"=>1,"c"=>3,"b"=>2,"d"=>4}
many =100_000
Benchmark.bm do|b|
GC.start
b.report("hash sort")do
many.times doHash[h.sort]endend
GC.start
b.report("keys sort")do
many.times do
nh ={}
h.keys.sort.each do|k|
nh[k]= h[k]endendendend
user system total real
hash sort 0.4000000.0000000.400000(0.405588)
keys sort 0.2500000.0100000.260000(0.260303)
Para grandes hashes, a diferença crescerá até 10x e mais
Você deu a melhor resposta para si mesmo no OP: Hash[h.sort]se você deseja mais possibilidades, aqui está a modificação no local do hash original para classificá-lo:
Corrigi o link para apontar para o Google, caso algum historiador queira pesquisar como isso poderia ter sido feito no passado. Mas qualquer um que venha agora deve usar uma versão mais recente do Ruby.
@equipments é um hash que eu construo no meu modelo e retorno no meu controlador. Se você chamar .sort, ele classificará o hash com base no seu valor-chave.
Eu fiz uma mini turma, chamei class AlphabeticalHash. Ele também tem um método chamado ap, que aceita um argumento, uma Hash, como entrada: ap variable. Semelhante a pp ( pp variable)
Mas (tentará) imprimirá na lista alfabética (suas chaves). Não sei se alguém mais quer usar isso, ele está disponível como uma jóia, você pode instalá-lo da seguinte forma:gem install alphabetical_hash
Para mim, isso é bastante simples. Se outras pessoas precisarem de mais funcionalidades, entre em contato, incluí-las na gema.
Edição: Crédito vai para Peter , que me deu a idéia. :)
each
oueach_pair
iterar sobre ele. Mesmo assim, eu provavelmente ainda pegaria as chaves, classificá-las e iterar sobre elas, pegando os valores conforme necessário. Isso garante que o código se comporte corretamente nos Rubies mais antigos.Respostas:
No Ruby 2.1, é simples:
fonte
h.sort{|a,z|a<=>z}.to_h
(testado 2.1.10, 2.3.3)a
é uma matriz, não apenas a chave). Eu apaguei meu comentário.h.map(&:sort).map(&:to_h)
.Nota: Ruby> = 1.9.2 possui um hash de preservação de ordem: as chaves de pedido são inseridas e serão as que estão enumeradas. O abaixo se aplica a versões mais antigas ou a códigos compatíveis com versões anteriores.
Não há conceito de um hash classificado. Então não, o que você está fazendo não está certo.
Se você deseja classificá-lo para exibição, retorne uma string:
ou, se você quiser as chaves em ordem:
ou, se você deseja acessar os elementos em ordem:
mas, em resumo, não faz sentido falar sobre um hash classificado. Nos documentos , "A ordem na qual você percorre um hash por chave ou valor pode parecer arbitrária e geralmente não estará na ordem de inserção". Portanto, inserir chaves em uma ordem específica no hash não ajudará.
fonte
Eu sempre usei
sort_by
. Você precisa agrupar a#sort_by
saídaHash[]
para gerar um hash, caso contrário, ela gera uma matriz de matrizes. Como alternativa, para fazer isso, você pode executar o#to_h
método na matriz de tuplas para convertê-las em umak=>v
estrutura (hash).Existe uma pergunta semelhante em " Como classificar um Ruby Hash pelo valor numérico? ".
fonte
sort_by
um hash retornará uma matriz. Você precisaria mapeá-lo como um hash novamente.Hash[hsh.sort_by{|k,v| v}]
hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}
.to_h
são suportadas apenas no Ruby 2.1.0+sort_by{|k,v| v}.to_h)
Não, não é (Ruby 1.9.x)
Para grandes hashes, a diferença crescerá até 10x e mais
fonte
Você deu a melhor resposta para si mesmo no OP:
Hash[h.sort]
se você deseja mais possibilidades, aqui está a modificação no local do hash original para classificá-lo:fonte
Com desestruturação e Hash # sort
Enumerável # sort_by
Classificação de hash # com comportamento padrão
Nota: <Ruby 2.1
Nota:> Ruby 2.1
fonte
v
, você deve prefixar um sublinhadohash.sort_by { |k, _v| k }.to_h
ActiveSupport :: OrderedHash é outra opção se você não quiser usar o ruby 1.9.2 ou executar suas próprias soluções alternativas.
fonte
fonte
Eu tive o mesmo problema (tive que classificar meus equipamentos pelo nome) e resolvi assim:
@equipments é um hash que eu construo no meu modelo e retorno no meu controlador. Se você chamar .sort, ele classificará o hash com base no seu valor-chave.
fonte
Gostei da solução no post anterior.
Eu fiz uma mini turma, chamei
class AlphabeticalHash
. Ele também tem um método chamadoap
, que aceita um argumento, umaHash
, como entrada:ap variable
. Semelhante a pp (pp variable
)Mas (tentará) imprimirá na lista alfabética (suas chaves). Não sei se alguém mais quer usar isso, ele está disponível como uma jóia, você pode instalá-lo da seguinte forma:
gem install alphabetical_hash
Para mim, isso é bastante simples. Se outras pessoas precisarem de mais funcionalidades, entre em contato, incluí-las na gema.
Edição: Crédito vai para Peter , que me deu a idéia. :)
fonte