Jak iterować poprzez Hash (z hashów) w Perlu?
Mam Hash, gdzie wartości kluczy są innymi Hashami.
Przykład: {'key' => {'key2' => {'key3' => 'value'}}}
Jak mogę iterować przez tę strukturę?
9 answers
Tego chcesz? (untested)
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...
};
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-02 13:10:10
Ta odpowiedź opiera się na idei Dave ' a Hintona-mianowicie, aby napisać podprogram ogólnego przeznaczenia, aby przejść strukturę haszującą. Taki hash walker pobiera odniesienie do kodu i po prostu wywołuje ten kod dla każdego węzła liścia w hashu.
Przy takim podejściu, ten sam hash walker może być używany do wielu rzeczy, w zależności od tego, które wywołanie zwrotne mu podamy. Aby uzyskać jeszcze większą elastyczność, musisz przekazać dwa wywołania zwrotne - jedno do wywołania, gdy wartość jest odwołaniem hash, a drugie do wywołaj, gdy jest zwykłą wartością skalarną. Strategie takie jak ta zostały dokładniej zbadane w doskonałej książce marca Jasona Dominusa, Perl wyższego rzędu.
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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-02 18:31:16
Ten post może być przydatny.
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
# .
# .
# .
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:00
Wcześniejsze odpowiedzi pokazują, jak wykonać własne rozwiązanie, co warto zrobić przynajmniej raz, aby zrozumieć, jak działają odniesienia i struktury danych w Perlu. Zdecydowanie powinieneś przeczytać perldoc perldsc i perldoc perlref, Jeśli jeszcze tego nie zrobiłeś.
Nie musisz jednak pisać własnego rozwiązania - istnieje już moduł na CPAN, który będzie iteracją przez dowolnie złożone struktury danych: Data::Visitor .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-02 19:20:38
Proszę również przeczytać perldoc perldsc. Możesz dowiedzieć się o hashach w głębi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-02 13:01:20
To nie jest tak naprawdę nowa odpowiedź, ale chciałem się podzielić, jak zrobić więcej niż wystarczy wypisać rekurencyjnie wszystkie wartości skrótu, ale także zmodyfikować je w razie potrzeby.
Oto moja tak drobna modyfikacja odpowiedzi dave4420, w której wartość jest przekazywana do wywołania zwrotnego jako odniesienie, więc moje wywołanie zwrotne wtedy funkcja może zmodyfikować każdą wartość w hash.
Musiałem też przebudować hash, gdy każda pętla tworzy kopie nie referencje.
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";
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-29 17:43:05
Będziesz musiał przejść przez nią dwa razy. tj.
while ( ($family, $roles) = each %HoH ) {
print "$family: ";
while ( ($role, $person) = each %$roles ) {
print "$role=$person ";
}
print "\n";
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-02 12:51:30
foreach my $keyname (keys(%foo) {
my $subhash = $foo{$keyname};
# stuff with $subhash as the value at $keyname
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-02 13:11:59
Jeśli używasz Perla jako "interpretera CPAN" to oprócz Data::Visitor
oraz Data::Deep
jest super proste 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;
Wyjście :
t => 10
y => 11
$a
i {[6] } są tu traktowane jako zmienne specjalne (jak w przypadku sort()
), podczas gdy wewnątrz funkcji traverse()
. Data::Traverse
jest bardzo prostym, ale niezwykle użytecznym modułem bez żadnych innych zależności.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-11 20:15:16