No estoy seguro de que haya mucha ventaja en ordenar un hash, a menos que lo esté utilizando eacho each_pairpara 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.
The Tin Man
Tiene sentido en ruby 1.9 también. Tenía una colección de citas agrupadas por fechas (como claves) provenientes de db y las clasifiqué manualmente a través de ruby. P.ej. {"2012-09-22": [...], "2012-09-30": [...], "2012-10-12": [...]}
Adit Saxena
Sí, creo que su proceso Hash [h.sort] es más efectivo que ordenar las claves y luego acceder nuevamente al hash a través de las claves ordenadas.
@zachaysan pero funciona: h.sort{|a,z|a<=>z}.to_h(probado 2.1.10, 2.3.3)
whitehat101
@ whitehat101 Tienes razón. Tuve un error ( aes una matriz, no solo la clave). He eliminado mi comentario
zachaysan
Sólo en caso de que otra persona está buscando una manera de ordenar una matriz de valores hash, esto va a hacer el truco (donde h es la matriz): h.map(&:sort).map(&:to_h).
JM Janzen
82
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 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á.
"A partir del orden de inserción hash 1.9.2 se conservará", y es genial.
The Tin Man
2
Re mi primer comentario (se siente divertido): por ejemplo, confiar en el pedido de hash se rompería silenciosa e impredeciblemente para las versiones de Ruby anteriores a 1.9.2.
Jo Liss
55
¿Cómo obtuvo esta respuesta alrededor de 20 + 1 sin responder ni una de las dos partes de la pregunta OP? "1) ¿Sería (el ejemplo OP) la mejor manera de ordenar un hash, 2) y devolver el objeto Hash"? No envidio los +1 :) es justo después de leer la respuesta que aún me quedan las preguntas originales. Además, si el punto es que no existe un hash ordenado, mire los comentarios para la respuesta elegida a esta pregunta stackoverflow.com/questions/489139/…
jj_
64
Siempre he usado sort_by. Debe ajustar la #sort_bysalida Hash[]para que genere un hash, de lo contrario, genera una matriz de matrices. Alternativamente, para lograr esto, puede ejecutar el #to_hmétodo en la matriz de tuplas para convertirlas en una k=>vestructura (hash).
usar sort_byen un hash devolverá una matriz. Tendría que trazarlo como un hash nuevamente. Hash[hsh.sort_by{|k,v| v}]
stevenspiel
1
Sí, creo que la clase enumeradora interpreta los hashes como matrices
boulder_ruby
3
Derecho, una especie está en valores: hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}.
Cary Swoveland
1
Tenga en cuenta que las llamadas to_hsolo se admiten en Ruby 2.1.0+
Phrogz,
1
hay un error tipográfico en el comentario, corrección:sort_by{|k,v| v}.to_h)
jitter
13
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 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, 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:
Arreglé el enlace para que apunte a Google en caso de que algún historiador quiera investigar cómo podría haberse hecho en el pasado. Pero cualquiera que esté llegando a esto ahora debería estar usando una versión más reciente de Ruby.
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.Respuestas:
En Ruby 2.1 es simple:
fuente
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 comentarioh.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:
o, si quieres las llaves en orden:
o, si desea acceder a los elementos en orden:
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á.
fuente
Siempre he usado
sort_by
. Debe ajustar la#sort_by
salidaHash[]
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 unak=>v
estructura (hash).Hay una pregunta similar en " ¿Cómo ordenar un Ruby Hash por valor numérico? ".
fuente
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)
Para grandes hashes, la diferencia crecerá hasta 10 veces y más
fuente
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:fuente
Con desestructuración y Hash # sort
Enumerable # sort_by
Hash # sort con comportamiento predeterminado
Nota: <Ruby 2.1
Nota:> Ruby 2.1
fuente
v
, debehash.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.
fuente
fuente
Tuve el mismo problema (tuve que ordenar mis equipos por su nombre) y resolví así:
@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.
fuente
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 llamadoap
, que acepta un argumento, unHash
, 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. :)
fuente