Есть несколько проблем с вашим подходом, которые вы должны выяснить. Во-первых, что произойдет, если есть два конечных узла с одинаковым ключом? Является ли второй удар первым, игнорируется ли второй, должен ли вывод содержать их список? Вот один из подходов. Сначала мы строим плоский список пар ключ-значение, используя рекурсивную функцию для работы с другими глубинами хеша:
my %data = (
foo => {bar => {baz => 'hello'}},
fizz => {buzz => {bing => 'world'}},
fad => {bad => {baz => 'clobber'}},
);
sub flatten {
my $hash = shift;
map {
my $value = $$hash{$_};
ref $value eq 'HASH'
? flatten($value)
: ($_ => $value)
} keys %$hash
}
print join( ", " => flatten \%data), "\n";
# baz, clobber, bing, world, baz, hello
my %flat = flatten \%data;
print join( ", " => %flat ), "\n";
# baz, hello, bing, world # lost (baz => clobber)
Исправление может быть что-то вроде этого, которое создаст хэш из ссылок на массив, содержащий все значения:
sub merge {
my %out;
while (@_) {
my ($key, $value) = splice @_, 0, 2;
push @{ $out{$key} }, $value
}
%out
}
my %better_flat = merge flatten \%data;
В рабочем коде было бы быстрее передавать ссылки между функциями, но я здесь опущен для ясности.