Sarebbe questo il modo migliore per ordinare un hash e restituire un oggetto Hash (anziché 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}
Sarebbe questo il modo migliore per ordinare un hash e restituire un oggetto Hash (anziché 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}
Risposte:
In Ruby 2.1 è semplice:
h.sort.to_h
h.sort{|a,z|a<=>z}.to_h
(testato 2.1.10, 2.3.3)
a
è un array, non solo la chiave). Ho cancellato il mio commento.
h.map(&:sort).map(&:to_h)
.
Nota: Ruby> = 1.9.2 ha un hash di conservazione dell'ordine: le chiavi dell'ordine inserite saranno nell'ordine in cui sono elencate. Quanto segue si applica alle versioni precedenti o al codice compatibile con le versioni precedenti.
Non esiste un concetto di hash ordinato. Quindi no, quello che stai facendo non è giusto.
Se lo desideri ordinato per la visualizzazione, restituisci una stringa:
"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"
oppure, se si desidera che le chiavi siano in ordine:
h.keys.sort
oppure, se si desidera accedere agli elementi in ordine:
h.sort.map do |key,value|
# keys will arrive in order to this block, with their associated value.
end
ma in sintesi, non ha senso parlare di un hash ordinato. Dai documenti , "L'ordine in cui attraversi un hash per chiave o valore può sembrare arbitrario e generalmente non sarà nell'ordine di inserimento". Quindi l'inserimento di chiavi in un ordine specifico nell'hash non aiuta.
L'ho sempre usato sort_by
. È necessario racchiudere l' #sort_by
output Hash[]
per renderlo un hash, altrimenti emette un array di array. In alternativa, per eseguire ciò è possibile eseguire il #to_h
metodo sull'array di tuple per convertirle in una k=>v
struttura (hash).
hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h
C'è una domanda simile in " Come ordinare un Ruby Hash per valore numerico? ".
sort_by
un hash restituirà un array. Dovresti mapparlo di nuovo come hash. Hash[hsh.sort_by{|k,v| v}]
hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}
.
to_h
è supportata solo in Ruby 2.1.0+
sort_by{|k,v| v}.to_h)
No, non lo è (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)
Per i grandi hash la differenza aumenterà fino a 10 volte e più
Hai dato la migliore risposta a te stesso nel PO: Hash[h.sort]
se desideri più possibilità, ecco una modifica sul posto dell'hash originale per renderlo ordinato:
h.keys.sort.each { |k| h[k] = h.delete k }
Ordina l'hash per chiave , restituisce l'hash in Ruby
Con destrutturazione e Hash # sort
hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h
Enumerable # sort_by
hash.sort_by { |k, v| k }.to_h
Hash # sort con comportamento predefinito
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
dovresti hash.sort_by { |k, _v| k }.to_h
ActiveSupport :: OrderedHash è un'altra opzione se non vuoi usare ruby 1.9.2 o lanciare le tue soluzioni alternative.
@ordered = {}
@unordered.keys.sort.each do |key|
@ordered[key] = @unordered[key]
end
Ho avuto lo stesso problema (ho dovuto ordinare le mie apparecchiature in base al loro nome) e ho risolto in questo modo:
<% @equipments.sort.each do |name, quantity| %>
...
<% end %>
@equipments è un hash che costruisco sul mio modello e restituisco sul mio controller. Se chiami .sort ordinerà l'hash in base al suo valore chiave.
Mi è piaciuta la soluzione nel post precedente.
Ho fatto una mini-classe, l'ho chiamata class AlphabeticalHash
. Essa ha anche un metodo chiamato ap
, che accetta un argomento, un Hash
, come input: ap variable
. Simile a pp (pp variable
)
Ma verrà (provare e) stampare nell'elenco alfabetico (i suoi tasti). Non so se qualcun altro vuole usarlo, è disponibile come gemma, è possibile installarlo come tale:gem install alphabetical_hash
Per me, questo è abbastanza semplice. Se altri hanno bisogno di più funzionalità, fammi sapere, lo includerò nella gemma.
EDIT: Il merito va a Peter , che mi ha dato l'idea. :)
each
oeach_pair
per iterarlo. Anche allora, probabilmente afferroi ancora le chiavi, le ordinerei, quindi ripeterei su di esse afferrando i valori secondo necessità. Ciò garantisce che il codice si comporterà correttamente sui rubini più vecchi.