Как выполнить итерации через Хеш (Хешей) в Perl?

У меня есть Хеш, где значения ключей являются другими Хешами.

Пример: {'key' => {'key2' => {'key3' => 'value'}}}

Как я могу выполнить итерации через эту структуру?

16
задан Axeman 8 October 2010 в 21:19
поделиться

7 ответов

Вы этого хотите? (непроверено)

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...
};
12
ответ дан 30 November 2019 в 15:28
поделиться

Вам придется повторить это дважды. то есть

while ( ($family, $roles) = each %HoH ) {
   print "$family: ";
   while ( ($role, $person) = each %$roles ) {
      print "$role=$person ";
   }
print "\n";
}
0
ответ дан 30 November 2019 в 15:28
поделиться

Этот ответ основан на идее Дэйва Хинтона - а именно, написать подпрограмму общего назначения для просмотра хэш-структуры. Такая программа обхода хэша принимает ссылку на код и просто вызывает этот код для каждого узла листа в хэше.

При таком подходе одна и та же программа обхода хэша может быть использована для выполнения многих задач, в зависимости от того, какой обратный вызов мы ей дадим. Для еще большей гибкости вам нужно передать два обратных вызова - один для вызова, когда значение является хэш-ссылкой, а другой для вызова, когда это обычное скалярное значение. Подобные стратегии более подробно рассматриваются в отличной книге Марка Джейсона Доминуса, 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);
23
ответ дан 30 November 2019 в 15:28
поделиться

Этот пост может быть полезен.

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
            # .
            # .
            # .
        }
    }
}
7
ответ дан 30 November 2019 в 15:28
поделиться

Предыдущие ответы показывают, как развернуть собственное решение, что хорошо сделать хотя бы один раз, чтобы вы понимали, как работают ссылки и структуры данных Perl . Вам обязательно стоит прочитать perldoc perldsc и perldoc perlref , если вы еще этого не сделали.

Однако вам не нужно писать собственное решение - на CPAN уже есть модуль, который будет выполнять итерацию через произвольно сложные структуры данных за вас: Data :: Visitor .

7
ответ дан 30 November 2019 в 15:28
поделиться

Также, пожалуйста, прочитайте perldoc perldsc. Вы можете подробно узнать о хэшах

5
ответ дан 30 November 2019 в 15:28
поделиться
foreach my $keyname (keys(%foo) {
  my $subhash = $foo{$keyname};
  # stuff with $subhash as the value at $keyname
}
0
ответ дан 30 November 2019 в 15:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: