2011-08-19 12 views
5

Creo que esta es la forma en la que normalmente ordenar un hash de valor:un hash de valor cuando tiene muchas claves

foreach my $key (sort { $hash{$a} <=> $hash{$b} } (keys %hash)) { 
    print "$key=>$hash{$key}"; 
} 

Esto imprimir los valores de menor a mayor.

Ahora, lo que si tengo un hash de esta manera:

$hash{$somekey}{$somekey2}{$thirdkey} 

¿Cómo podría ordenar por valores y obtener todas las claves, así?

+0

¿Desea ordenar independientemente de la profundidad dentro de la estructura? – DavidO

+0

Hay una profundidad fija de 3 claves en este hash, y quiero ordenar el hash por el valor de todos los trillizos de claves que existen. – petranaya

Respuesta

3

me acaba de crear una nueva almohadilla:

my %new; 
for my $k1 (keys %hash) { 
    for my $k2 (keys %{$hash{$k1}}) { 
    for my $k3 (keys %{$hash{$k1}{$k2}}) { 
     $new{$k1,$k2,$k3} = $hash{$k1}{$k2}{$k3}; 
    } 
    } 
} 

my @ordered = sort { $new{$a} <=> $new{$b} } keys %new; 
for my $k (@ordered) { 
    my @keys = split($;, $k); 
    print "key: @k  - value: $new{$k}\n"; 
} 
+0

Gracias, acabo de usar esto. – petranaya

+2

Tenga en cuenta que '$;' tiene que ser un valor que * nunca aparezca en sus claves * (por defecto es "\ x1c", un carácter de control), de lo contrario este código se bloqueará y se quemará. – hobbs

+0

@FMc - gracias! post corregido – ErikR

1

Aquí está una manera de hacerlo utilizando Deep::Hash::Utils.

use Deep::Hash::Utils qw(slurp); 

my %h = (
    A => { 
     Aa => { Aaa => 4, Aab => 5 }, 
     Ab => { Aba => 1 }, 
     Ac => { Aca => 2, Acb => 9, Acc => 0 }, 
    }, 
    B => { 
     Ba => { Baa => 44, Bab => -55 }, 
     Bc => { Bca => 22, Bcb => 99, Bcc => 100 }, 
    }, 
); 

my @all_keys_and_vals = slurp \%h; 
print "@$_\n" for sort { $a->[-1] <=> $b->[-1] } @all_keys_and_vals; 

Salida:

B Ba Bab -55 
A Ac Acc 0 
A Ab Aba 1 
A Ac Aca 2 
A Aa Aaa 4 
A Aa Aab 5 
A Ac Acb 9 
B Bc Bca 22 
B Ba Baa 44 
B Bc Bcb 99 
B Bc Bcc 100 
1

he hecho algo similar moviendo una referenciaa la tecla de almohadilla apropiada. A continuación, puede realizar el orden en el puntero.

La ventaja de hacerlo de esta manera es que es fácil de ajustar si el nivel cambia.

Lo que he usado para esta metodología es mover sistemáticamente el puntero a un nivel específico al hacer referencia a una matriz de teclas. (Por ejemplo: my @Keys = ('Value', 'Value2');)

Creo que un derivado del siguiente ejemplo podría darle lo que está buscando.

my $list_ref; 
my $pointer; 

my %list = (
    Value => { 
     Value2 => { 
     A => '1', 
     C => '3', 
     B => '2', 
     }, 
    }, 
); 

$list_ref = \%list; 
$pointer = $list_ref->{Value}->{Value2}; 

foreach my $key (sort { $pointer->{$a} <=> $pointer->{$b} } (keys %{$pointer})) { 
    print "Key: $key\n"; 
} 
1

Para fines académicos, aquí es una función recursiva bastante ordenada:

sub flatten_hash { 
    my ($hash, $path) = @_; 
    $path = [] unless defined $path; 

    my @ret; 

    while (my ($key, $value) = each %$hash) { 
    if (ref $value eq 'HASH') { 
     push @ret, flatten_hash($value, [ @$path, $key ]); 
    } else { 
     push @ret, [ [ @$path, $key ], $value ]; 
    } 
    } 

    return @ret; 
} 

que tiene un hash como

{ 
    roman => { 
     i => 1, 
     ii => 2, 
     iii => 3, 
    }, 
    english => { 
     one => 1, 
     two => 2, 
     three => 3, 
    }, 
} 

y lo convierte en una lista como

(
    [ ['roman','i'], 1 ], 
    [ ['roman', 'ii'], 2 ], 
    [ ['roman', 'iii'], 3 ], 
    [ ['english', 'one'], 1 ], 
    [ ['english', 'two'], 2 ], 
    [ ['english', 'three'], 3 ] 
) 

aunque por supuesto t El orden está destinado a variar. Dada esa lista, puede ordenarla en { $a->[1] <=> $b->[1] } o similar, y luego extraer la ruta de la clave desde @{ $entry->[0] } para cada entrada. Funciona independientemente de la profundidad de la estructura de datos, e incluso si los nodos de hoja no ocurren todos a la misma profundidad. Sin embargo, necesita un poco de extensión para tratar con estructuras que no son puramente de hashrefs y escalares simples.

Cuestiones relacionadas