2009-04-13 16 views
5

Quiero ordenar un hash que en realidad tiene un hash como valor. Por ejemplo:¿Cómo puedo ordenar un hash de hash por clave en Perl?

my %hash1=(
    field1=>"", 
    field2=>"", 
    count=>0, 
); 
my %hash2; 
$hash2{"asd"}={%hash1}; 

y me inserta un montón de hashes a %hash2 con diferentes valores de recuento de %hash2.

¿Cómo puedo ordenar el %hash1 de acuerdo con un valor de recuento de hash1?

¿Hay alguna manera de hacer esto sin implementar manualmente el quicksort, por ejemplo con la función de ordenamiento de Perl?

+0

¿Quiere decir que desea obtener la lista de hashes (como hash1) ordenados según el recuento de los valores en hash2? – Jagmal

+0

yes Jagmal eso significa que quiero ordenar con respecto a $ hash2 {"asd"} {count}. – systemsfault

Respuesta

10
my @hash1s = sort {$a->{count} <=> $b->{count}} values %hash2; 
+0

Lo intenté pero recibí la siguiente advertencia: [advertencia]: Uso del valor no inicializado en comparación numérica (<=>) en – systemsfault

+0

El fragmento de código tanto de mi respuesta como de mi respuesta me funciona cuando la pruebo (incluso con -w y "use strict"). –

+0

recibe esa advertencia porque uno o más de sus valores hash no tienen valor para la tecla 'conteo'. Si desea contarlos como 0, podría hacer una ordenación {($ a -> {count} || 0) <=> ($ b -> {count} || 0)} values% hash2; – nohat

1

Si desea obtener la lista de hashes (como hash1) ordenados según el recuento de los valores en hash2, esto puede ayudar:

@sorted_hash1_list = sort sort_hash_by_count_key($a, $b) (values (%hash2); 


# This method can have any logic you want 
sub sort_hash_by_count_key { 
    my ($a, $b) = @_; 
    return $a->{count} <=> $b->{count}; 
} 
+0

¿Quiere decir "ordenar \ & sort_hash_by_count_key, values% hash2" en lugar de lo que tiene actualmente? –

+0

Supongo que esto funcionará de esta manera también, ¿no? – Jagmal

0

Ver http://perldoc.perl.org/functions/sort.html para la porción de contexto cómo funciona ordenar en Perl.

Y he aquí un ejemplo ... tratando de ser legible, no pernicioso.

#!/usr/bin/perl 
# Sort Hash of Hashes by sub-hash's element count. 
use warnings; 
use strict; 


my $hash= { 
      A=>{C=>"D",0=>"r",T=>"q"} 
      ,B=>{} 
      ,C=>{E=>"F",G=>"H"} 
      }; 

sub compareHashKeys {0+(keys %{$hash->{$a}}) <=> 0+(keys %{$hash->{$b}}) } 

my @SortedKeys = sort compareHashKeys keys %{$hash}; 
print join ("," , @SortedKeys) ."\n"; 
+0

¿para qué es '0+'? – systemsfault

+0

El 0+ se supone que coacciona el valor a un valor numérico, sin embargo, <=> ya lo hace, por lo que el 0+ es realmente redundante. :-P –

+0

Bueno, el valor que sale de cmp o <=> ya es numérico, es -1, 0 o 1. No importa de qué datos se trate. sort() necesita -1, 0 o 1 para decidir cómo ordenar cosas. –

6

De perlfaq4, la respuesta a "http://faq.perl.org/perlfaq4.html#How_do_I_sort_a_hash" tiene la mayor parte de la información que necesita para armar su código.

Es posible que también quiera ver el capítulo sobre Ordenando en Learning Perl.

Chris tiene una respuesta completamente buena, aunque odio usar values así. Una forma más familiar para hacer la misma cosa es ir a través de las claves del hash de nivel superior, pero ordenar por la clave de segundo nivel:

my @sorted_hashes = 
    sort { $hash2->{$a}{count} <=> $hash2->{$b}{count} } 
    keys %hash2; 

lo hago de esta manera porque es un poco menos endiablada .


¿Cómo puedo ordenar un hash (opcionalmente por valor en lugar de clave)?

(aportado por Brian D Foy)

Para ordenar un hash, empezar con las teclas. En este ejemplo, proporcionamos la lista de claves para la función de clasificación que luego las compara ASCIIbetically (lo que puede verse afectado por la configuración de su configuración regional). La lista de salida tiene las teclas en orden ASCIIbético. Una vez que tenemos las claves, podemos revisarlas para crear un informe que enumera las claves en orden ASCIIbético.

my @keys = sort { $a cmp $b } keys %hash; 

foreach my $key (@keys) 
    { 
    printf "%-20s %6d\n", $key, $hash{$key}; 
    } 

Sin embargo, podríamos obtener más fantasía en el bloque sort(). En lugar de comparar las claves, podemos calcular un valor con ellas y usar ese valor como comparación.

Por ejemplo, para hacer que el orden de nuestros informes no distinga entre mayúsculas y minúsculas, usamos la secuencia \ L en una cadena de comillas dobles para que todo esté en minúscula. El bloque de clasificación() compara los valores en minúscula para determinar en qué orden colocar las claves.

my @keys = sort { "\L$a" cmp "\L$b" } keys %hash; 

Nota: si el cómputo es caro o el hash tiene muchos elementos, es posible que desee buscar en el Schwartzian Transform para almacenar en caché los resultados del cálculo.

Si, en cambio, queremos ordenar por el valor hash, usamos la tecla hash para buscarlo. Todavía obtenemos una lista de claves, pero esta vez están ordenadas por su valor.

my @keys = sort { $hash{$a} <=> $hash{$b} } keys %hash; 

A partir de ahí podemos volvernos más complejos. Si los valores hash son los mismos, podemos proporcionar una ordenación secundaria en la tecla hash.

my @keys = sort { 
    $hash{$a} <=> $hash{$b} 
     or 
    "\L$a" cmp "\L$b" 
    } keys %hash; 
+0

wow gran explicación thanx. – systemsfault

0

Para ordenar por el uso numérico < => y para el uso de la cadena cmp.

# sort by the numeric count field on inner hash 
# 
foreach my $key (sort {$hash2{$a}->{'count'} <=> $hash2{$b}->{'count'}} keys %hash2) { 
    print $key,$hash2{$key}->{'count'},"\n"; 
} 

# sort by the string field1 (or field2) on the inner hash 
# 
foreach my $key (sort {$hash2{$a}->{'field1'} cmp $hash2{$b}->{'field1'}} keys %hash2) { 
    print $key,$hash2{$key}->{'field1'},"\n"; 
} 

Para invertir el orden simplemente intercambiar $ ay $ b:

# sort by the numeric count field on inner hash 
# 
foreach my $key (sort {$hash2{$a}->{'count'} <=> $hash2{$b}->{'count'}} keys %hash2) { 
    print $key,$hash2{$key}->{'count'},"\n"; 
} 

# sort by the string field1 (or field2) on the inner hash 
# 
foreach my $key (sort {$hash2{$a}->{'field1'} cmp $hash2{$b}->{'field1'}} keys %hash2) { 
    print $key,$hash2{$key}->{'field1'},"\n"; 
} 
Cuestiones relacionadas