Essa seria a melhor maneira de classificar um hash e retornar o objeto 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}
Essa seria a melhor maneira de classificar um hash e retornar o objeto 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}
Respostas:
No Ruby 2.1, é simples:
h.sort.to_h
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:
"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"
ou, se você quiser as chaves em ordem:
h.keys.sort
ou, se você deseja 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 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á.
Eu sempre usei sort_by
. Você precisa agrupar a #sort_by
saí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_h
método na matriz de tuplas para convertê-las em uma k=>v
estrutura (hash).
hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h
Existe uma pergunta semelhante em " Como classificar um Ruby Hash pelo valor numérico? ".
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)
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á a modificação no local do hash original para classificá-lo:
h.keys.sort.each { |k| h[k] = h.delete k }
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
Classificação de hash # com comportamento padrão
h = { "b" => 2, "c" => 1, "a" => 3 }
h.sort # e.g. ["a", 20] <=> ["b", 30]
hash.sort.to_h #=> { "a" => 3, "b" => 2, "c" => 1 }
Nota: <Ruby 2.1
array = [["key", "value"]]
hash = Hash[array]
hash #=> {"key"=>"value"}
Nota:> Ruby 2.1
[["key", "value"]].to_h #=> {"key"=>"value"}
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.
@ordered = {}
@unordered.keys.sort.each do |key|
@ordered[key] = @unordered[key]
end
Eu tive o mesmo problema (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-chave.
Gostei da solução no post anterior.
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.