Página 1 de 1

Ordenando un hash por sus valores y por sus llaves

NotaPublicado: 2012-07-02 13:10 @590
por MARKO
Saludos, Perl en Español.

Necesito ordenar el siguiente hash de horas->precio:
sin orden.png
sin orden.png (7.59 KiB) Visto 760 veces
(el ingreso es 1->precio, 2->precio, 3->precio y así sucesivamente pero al imprimir el hash sale en el orden mostrado.

Curioseando en el foro me fui hacia un articulo que Uds. recomendaron y escribí esto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. foreach my $hora( sort ordenar_por_valor keys %precio) {
  2.   my $valor = $precio{$hora};
  3.   print "$hora => $valor\n";
  4. }
  5.  
  6. sub ordenar_por_valor {
  7.   return $precio{$a} <=> $precio{$b};
  8. }
  9.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

el cual nos da el siguiente resultado:
orden parcial.png
orden parcial.png (10.06 KiB) Visto 760 veces


Como podrán ver, la hora (1,2,3,4,5,24) tienen el precio menor y las horas (19, 20, 21 y 22) tienen el precio mayor.

A mi solo me interesa el precio menor y el mayor pero con la primera hora con que apareció algo así:

%precio [
1 = > 140.65300329,
2 = > 140.65300329,
3 = > 140.65300329,
4 = > 140.65300329,
5 = > 140.65300329,
24 = > 140.65300329,
.
.
.
.
19 = > 167.96513356
20 = > 167.96513356
21 = > 167.96513356
22 = > 167.96513356
]

simplemente es coincidencia que el precio menor haya quedado en las primeras horas y el mayor en las últimas, podría haber sucedido en cualquier hora del día pero lo que me interesa es que se ordenen primeramente por el precio y luego por su llave.

¿Tengo el enfoque correcto o sería mejor meterlo en un arreglo y hacer el proceso "burbuja" para ordenar? ¿Ideas?

Gracias por adelantado.

Re: Ordenando un hash por sus valores y por sus llaves

NotaPublicado: 2012-07-02 14:06 @629
por explorer
El almacenamiento de información dentro de un hash siempre es orden "aleatorio".

Para ordenador por los precios, y además, por las horas, solo hay que modificar un poco la condición de comparación (no probado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub ordenar_por_valor {
  2.     return
  3.         $precio{$a} <=> $precio{$b}
  4.                      ||
  5.                 $a  <=> $b
  6.     ;
  7. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
De esa manera, estamos primero comparando -numéricamente y por orden ascendente- por el precio, y en el caso de igualdad de precio, el orden lo define la comparación -también numéricamente y por orden ascendente- de los valores de las claves (las horas).

Otra opción: como solo hay un precio por hora, podrías haber usado un array, y te ahorrabas algo de código.

Edito: hummm, quizás no te ahorras tanto código como yo creía.

Re: Ordenando un hash por sus valores y por sus llaves

NotaPublicado: 2012-07-02 16:59 @749
por MARKO
Gracias por tu pronta respuesta.

Probé con el código que recomiendas, el orden cambió un poco pero no es el óptimo. Además aparecen muchas líneas de advertencia de error "odd number of elements in anonymous hash":
OTRO ORDEN.png
OTRO ORDEN.png (21.69 KiB) Visto 728 veces


¿Qué me recomiendas hacer si solo me interesa obtener el valor mínimo y la primera hora a la que este valor ocurrió y lo mismo para el valor máximo; el valor máximo y la primera hora a la que este valor ocurrió?

Las demás horas y precios pueden ser obviadas.

Otra opción: como solo hay un precio por hora, podrías haber usado un array, y te ahorrabas algo de código.

¿Método de ordenamiento burbuja o qué me recomiendas? De que no es menos código estoy seguro.

Gracias por adelantado.

Re: Ordenando un hash por sus valores y por sus llaves

NotaPublicado: 2012-07-03 01:30 @104
por explorer
Por favor, no publiques volcados gráficos. Copia y pega siempre texto. Veo que es una consola de MSDOS, y sí que puedes copiar ese texto, con el ratón.

MARKO escribiste:Probé con el código que recomiendas, el orden cambió un poco pero no es el óptimo. Además aparecen muchas líneas de advertencia de error "odd number of elements in anonymous hash":
OTRO ORDEN.png
Sin ver un código de ejemplo, es difícil decir qué pasa.
El mensaje de error dice que el hash tiene un número impar de elementos, así que se te está colando algún elemento, o pones un elemento de más, o algo así.

MARKO escribiste:¿Qué me recomiendas hacer si solo me interesa obtener el valor mínimo y la primera hora a la que este valor ocurrió y lo mismo para el valor máximo; el valor máximo y la primera hora a la que este valor ocurrió?
Es muy sencillo: ordenas el hash como te indiqué, y luego solo hay que leer el primer par y el último par.

MARKO escribiste:¿Método de ordenamiento burbuja o qué me recomiendas?
Nada, no hay que hacer nada de eso. Con ordenarlo una vez, vale.

Edito: Este es un ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.14;
  3.  
  4. my %precios = (
  5.     1   => 140.65,
  6.     2   => 140.65,
  7.     3   => 140.65,
  8.     4   => 140.65,
  9.     5   => 140.65,
  10.     6   => 150.27,
  11.     7   => 154.12,
  12.     8   => 163.73,
  13.     9   => 162.60,
  14.     10  => 154.12,
  15.     11  => 154.12,
  16.     12  => 154.12,
  17.     13  => 154.12,
  18.     14  => 163.73,
  19.     15  => 163.73,
  20.     16  => 163.73,
  21.     17  => 163.73,
  22.     18  => 163.73,
  23.     19  => 167.97,
  24.     20  => 167.97,
  25.     21  => 167.97,
  26.     22  => 167.97,
  27.     23  => 150.27,
  28.     24  => 140.65,
  29. );
  30.  
  31. my @horas_ordenadas = sort { $precios{$a} <=> $precios{$b} || $a <=> $b } keys %precios;
  32.  
  33. for (@horas_ordenadas) {
  34.     say "$_ => $precios{$_}";
  35. }
  36.  
  37. my $hora_precio_mas_bajo = 0;
  38. my $hora_precio_mas_alto = $#horas_ordenadas;
  39.  
  40. while ($hora_precio_mas_alto > 0) {                     # encontrar la primera hora con precio más alto
  41.     last if $precios{$horas_ordenadas[$hora_precio_mas_alto-1]} != $precios{$horas_ordenadas[-1]};
  42.  
  43.     $hora_precio_mas_alto--;
  44. }
  45.  
  46. say "Precio más bajo: $precios{$horas_ordenadas[$hora_precio_mas_bajo]}";
  47. say "Primera hora con ese precio: $horas_ordenadas[$hora_precio_mas_bajo]";
  48. say "Precio más alto: $precios{$horas_ordenadas[$hora_precio_mas_alto]}";
  49. say "Primera hora con ese precio: $horas_ordenadas[$hora_precio_mas_alto]";
  50.  
  51. __END__
  52. 1 => 140.65
  53. 2 => 140.65
  54. 3 => 140.65
  55. 4 => 140.65
  56. 5 => 140.65
  57. 24 => 140.65
  58. 6 => 150.27
  59. 23 => 150.27
  60. 7 => 154.12
  61. 10 => 154.12
  62. 11 => 154.12
  63. 12 => 154.12
  64. 13 => 154.12
  65. 9 => 162.6
  66. 8 => 163.73
  67. 14 => 163.73
  68. 15 => 163.73
  69. 16 => 163.73
  70. 17 => 163.73
  71. 18 => 163.73
  72. 19 => 167.97
  73. 20 => 167.97
  74. 21 => 167.97
  75. 22 => 167.97
  76. Precio más bajo: 140.65
  77. Primera hora con ese precio: 1
  78. Precio más alto: 167.97
  79. Primera hora con ese precio: 19
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Re: Ordenando un hash por sus valores y por sus llaves

NotaPublicado: 2012-07-05 13:57 @623
por MARKO
Perfecto, explorer, me ayudaste muchísimo.

Muchísimas gracias.