sort perl hash perl-data-structures

sort - perl hash



¿Cómo iterar a través de Hash(de Hashes) en Perl? (9)

¿Es esto lo que quieres? (no probado)

sub for_hash { my ($hash, $fn) = @_; while (my ($key, $value) = each %$hash) { if (''HASH'' eq ref $value) { for_hash $value, $fn; } else { $fn->($value); } } } my $example = {''key'' => {''key2'' => {''key3'' => ''value''}}}; for_hash $example, sub { my ($value) = @_; # Do something with $value... };

Tengo Hash donde los valores de las claves son otros Hashes.

Ejemplo: {''key'' => {''key2'' => {''key3'' => ''value''}}}

¿Cómo puedo recorrer esta estructura?


Esta no es realmente una nueva respuesta, pero quería compartir cómo hacer más que simplemente imprimir todos los valores de hash de forma recursiva, pero también modificarlos si es necesario.

Aquí está mi muy pequeña modificación de la respuesta del dave4420 en la cual el valor se pasa a la devolución de llamada como una referencia para que mi rutina de devolución de llamada pueda modificar cada valor en el hash.

También tuve que reconstruir el hash ya que mientras cada bucle crea copias y no referencias.

sub hash_walk { my $self = shift; my ($hash, $key_list, $callback) = @_; while (my ($k, $v) = each %$hash) { # Keep track of the hierarchy of keys, in case # our callback needs it. push @$key_list, $k; if (ref($v) eq ''HASH'') { # Recurse. $self->hash_walk($v, $key_list, $callback); } else { # Otherwise, invoke our callback, passing it # the current key and value, along with the # full parentage of that key. $callback->($k, /$v, $key_list); } pop @$key_list; # Replace old hash values with the new ones $hash->{$k} = $v; } } hash_walk(/%prj, [], /&replace_all_val_strings); sub replace_all_val_strings { my ($k, $v, $key_list) = @_; printf "k = %-8s v = %-4s key_list = [%s]/n", $k, $$v, "@$key_list"; $$v =~ s/oldstr/newstr/; printf "k = %-8s v = %-4s key_list = [%s]/n", $k, $$v, "@$key_list"; }


Esta respuesta se basa en la idea detrás de Dave Hinton, a saber, escribir una subrutina de propósito general para recorrer una estructura hash. Dicho hash walker toma una referencia de código y simplemente llama a ese código para cada nodo de hoja en el hash.

Con este enfoque, el mismo hash walker se puede usar para hacer muchas cosas, dependiendo de la devolución de llamada que le demos. Para aún más flexibilidad, necesitaría pasar dos devoluciones de llamada: una para invocar cuando el valor es una referencia de hash y la otra para invocar cuando es un valor escalar ordinario. Estrategias como esta se exploran con mayor profundidad en el excelente libro de Marc Jason Dominus, Higher Order Perl .

use strict; use warnings; sub hash_walk { my ($hash, $key_list, $callback) = @_; while (my ($k, $v) = each %$hash) { # Keep track of the hierarchy of keys, in case # our callback needs it. push @$key_list, $k; if (ref($v) eq ''HASH'') { # Recurse. hash_walk($v, $key_list, $callback); } else { # Otherwise, invoke our callback, passing it # the current key and value, along with the # full parentage of that key. $callback->($k, $v, $key_list); } pop @$key_list; } } my %data = ( a => { ab => 1, ac => 2, ad => { ada => 3, adb => 4, adc => { adca => 5, adcb => 6, }, }, }, b => 7, c => { ca => 8, cb => { cba => 9, cbb => 10, }, }, ); sub print_keys_and_value { my ($k, $v, $key_list) = @_; printf "k = %-8s v = %-4s key_list = [%s]/n", $k, $v, "@$key_list"; } hash_walk(/%data, [], /&print_keys_and_value);


Las respuestas anteriores muestran cómo hacer rodar su propia solución, lo cual es bueno hacerlo al menos una vez para que entienda las agallas de cómo funcionan las referencias de perl y las estructuras de datos. Definitivamente, debería leer a través de perldoc perldsc y perldoc perlref si aún no lo ha hecho.

Sin embargo, no es necesario que escriba su propia solución; ya hay un módulo en CPAN que recorrerá para usted estructuras de datos arbitrariamente complejas: Data::Visitor .


Si está utilizando perl como "intérprete de CPAN", además de Data::Visitor y Data::Deep , está el súper simple Data::Traverse :

use Data::Traverse qw(traverse); my %test_hash = ( q => [qw/1 2 3 4/], w => [qw/4 6 5 7/], e => ["8"], r => { r => "9" , t => "10" , y => "11" , } , ); traverse { next if /ARRAY/; print "$a => $b/n" if /HASH/ && $b > 8 } /%test_hash;

Salida :

t => 10 y => 11

$a y $b se tratan como variables especiales aquí (como con sort() ) mientras se encuentran dentro de la función traverse() . Data::Traverse es un módulo muy simple pero sumamente útil sin dependencias que no sean CORE.


También, por favor lea a través de perldoc perldsc . Puedes aprender sobre hashes en profundidad.


Tendrás que recorrerlo dos veces. es decir

while ( ($family, $roles) = each %HoH ) { print "$family: "; while ( ($role, $person) = each %$roles ) { print "$role=$person "; } print "/n"; }


Esta publicación puede ser útil.

foreach my $key (keys %hash) { foreach my $key2 (keys %{ $hash{$key} }) { foreach my $key3 (keys %{ $hash{$key}{$key2} }) { $value = $hash{$key}{$key2}->{$key3}; # . # . # Do something with $value # . # . # . } } }


foreach my $keyname (keys(%foo) { my $subhash = $foo{$keyname}; # stuff with $subhash as the value at $keyname }