Classificar hash por chave, retornar hash em Ruby

Essa seria a melhor maneira de classificar um hash e retornar o object Hash (em vez de Array):

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4} # => {"a"=>1, "c"=>3, "b"=>2, "d"=>4} Hash[h.sort] # => {"a"=>1, "b"=>2, "c"=>3, "d"=>4} 

No Ruby 2.1 é simples:

 h.sort.to_h 

Nota: Ruby> = 1.9.2 tem um hash de preservação de ordem: as chaves de ordem são inseridas será a ordem em que sã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ê quiser que ele seja classificado para exibição, retorne uma string:

 "{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}" 

ou, se você quiser as chaves em ordem:

 h.keys.sort 

ou, se você quiser acessar os elementos em ordem:

 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 ordenado. Dos documentos , “A ordem em que você percorre um hash por qualquer 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á.

Eu sempre usei o sort_by . Você precisa #sort_by saída #sort_by com Hash[] para fazer com que ela #sort_by um hash, caso contrário, ela gerará uma matriz de matrizes. Como alternativa, para realizar isso, você pode executar o método #to_h na matriz de tuplas para convertê-las em uma estrutura k=>v (hash).

 hsh ={"a" => 1000, "b" => 10, "c" => 200000} Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h 

Há uma pergunta semelhante em ” Como classificar um hash do Ruby por um valor numérico? “.

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 do Hash[h.sort] end end GC.start b.report("keys sort") do many.times do nh = {} h.keys.sort.each do |k| nh[k] = h[k] end end end end user system total real hash sort 0.400000 0.000000 0.400000 ( 0.405588) keys sort 0.250000 0.010000 0.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á uma modificação no local do hash original para torná-lo classificado:

 h.keys.sort.each { |k| h[k] = h.delete k } 

ActiveSupport :: OrderedHash é outra opção se você não quiser usar o ruby ​​1.9.2 ou rolar suas próprias soluções.

Classificar hash por chave , retornar hash em Ruby

Com desestruturação e Hash # sort

 hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h 

Enumerável # sort_by

 hash.sort_by { |k, v| k }.to_h 

Hash # sort com comportamento padrão

 h = { "b" => 2, "c" => 1, "a" => 3 } h.sort # eg ["a", 20] <=> ["b", 30] hash.sort.to_h #=> { "a" => 3, "b" => 2, "c" => 1 } 

Nota:

 array = [["key", "value"]] hash = Hash[array] hash #=> {"key"=>"value"} 

Nota:> Ruby 2.1

 [["key", "value"]].to_h #=> {"key"=>"value"} 

 @ordered = {} @unordered.keys.sort.each do |key| @ordered[key] = @unordered[key] end 

Eu tive o mesmo problema (eu tive que classificar meus equipamentos pelo nome) e resolvi assim:

 <% @equipments.sort.each do |name, quantity| %> ... <% end %> 

@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 de chave.

Gostei da solução no post anterior.

Eu fiz uma miniaula, chamada de class AlphabeticalHash . Também possui um método chamado ap , que aceita um argumento, um Hash , como input: ap variable . Semelhante a pp ( pp variable )

Mas irá (tentar) imprimir em lista alfabética (suas chaves). Não sei se alguém mais quiser usar isso, ele está disponível como uma jóia, você pode instalá-lo como tal: gem install alphabetical_hash

Para mim, isso é bem simples. Se os outros precisarem de mais funcionalidade, avise-me, includeei na gema.

EDIT: O crédito vai para Peter , que me deu a idéia. 🙂