¿Sería esta la mejor manera de ordenar un hash y devolver un objeto Hash (en lugar 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}
¿Sería esta la mejor manera de ordenar un hash y devolver un objeto Hash (en lugar 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}
Respuestas:
En Ruby 2.1 es simple:
h.sort.to_h
h.sort{|a,z|a<=>z}.to_h
(probado 2.1.10, 2.3.3)
a
es una matriz, no solo la clave). He eliminado mi comentario
h.map(&:sort).map(&:to_h)
.
Nota: Ruby> = 1.9.2 tiene un hash para preservar el orden: las claves de orden que se inserten serán el orden en que se enumeran. Lo siguiente se aplica a versiones anteriores o al código compatible con versiones anteriores.
No existe el concepto de un hash ordenado. Entonces no, lo que estás haciendo no está bien.
Si desea ordenarlo para su visualización, devuelva una cadena:
"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"
o, si quieres las llaves en orden:
h.keys.sort
o, si desea acceder a los elementos en orden:
h.sort.map do |key,value|
# keys will arrive in order to this block, with their associated value.
end
pero en resumen, no tiene sentido hablar de un hash ordenado. De los documentos , "El orden en que atraviesas un hash por clave o valor puede parecer arbitrario, y generalmente no estará en el orden de inserción". Por lo tanto, insertar claves en un orden específico en el hash no ayudará.
Siempre he usado sort_by
. Debe ajustar la #sort_by
salida Hash[]
para que genere un hash, de lo contrario, genera una matriz de matrices. Alternativamente, para lograr esto, puede ejecutar el #to_h
método en la matriz de tuplas para convertirlas en una k=>v
estructura (hash).
hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h
Hay una pregunta similar en " ¿Cómo ordenar un Ruby Hash por valor numérico? ".
sort_by
en un hash devolverá una matriz. Tendría que trazarlo como un hash nuevamente. Hash[hsh.sort_by{|k,v| v}]
hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}
.
to_h
solo se admiten en Ruby 2.1.0+
sort_by{|k,v| v}.to_h)
No, no lo es (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, la diferencia crecerá hasta 10 veces y más
Te diste la mejor respuesta en el OP: Hash[h.sort]
si anhelas más posibilidades, aquí hay una modificación en el lugar del hash original para ordenarlo:
h.keys.sort.each { |k| h[k] = h.delete k }
Ordenar hash por clave , devolver hash en Ruby
Con desestructuración y Hash # sort
hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h
Enumerable # sort_by
hash.sort_by { |k, v| k }.to_h
Hash # sort con comportamiento predeterminado
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
, debe hash.sort_by { |k, _v| k }.to_h
ActiveSupport :: OrderedHash es otra opción si no desea usar ruby 1.9.2 o usar sus propias soluciones.
@ordered = {}
@unordered.keys.sort.each do |key|
@ordered[key] = @unordered[key]
end
Tuve el mismo problema (tuve que ordenar mis equipos por su nombre) y resolví así:
<% @equipments.sort.each do |name, quantity| %>
...
<% end %>
@equipments es un hash que construyo en mi modelo y devuelvo en mi controlador. Si llama a .sort, ordenará el hash en función de su valor clave.
Me gustó la solución en la publicación anterior.
Hice una mini clase, la llamé class AlphabeticalHash
. También cuenta con un método llamado ap
, que acepta un argumento, un Hash
, como entrada: ap variable
. Similar a pp ( pp variable
)
Pero (intentará) imprimir en una lista alfabética (sus teclas). No sé si alguien más quiere usar esto, está disponible como una gema, puede instalarlo como tal:gem install alphabetical_hash
Para mí, esto es bastante simple. Si otros necesitan más funcionalidad, hágamelo saber, lo incluiré en la gema.
EDITAR: El crédito va a Peter , quien me dio la idea. :)
each
oeach_pair
para iterar sobre él. Incluso entonces, probablemente aún agarraría las claves, las ordenaría, luego las repetiría agarrando los valores según sea necesario. Eso asegura que el código se comportará correctamente en Rubíes más antiguos.