Для академических целей приведем довольно аккуратную рекурсивную функцию:
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;
}
, которая принимает хеш вроде
{
roman => {
i => 1,
ii => 2,
iii => 3,
},
english => {
one => 1,
two => 2,
three => 3,
},
}
и превращает его в список типа
(
[ ['roman','i'], 1 ],
[ ['roman', 'ii'], 2 ],
[ ['roman', 'iii'], 3 ],
[ ['english', 'one'], 1 ],
[ ['english', 'two'], 2 ],
[ ['english', 'three'], 3 ]
)
хотя, конечно, порядок должен меняться.Учитывая этот список, вы можете отсортировать его по { $a->[1] <=> $b->[1] }
или аналогичному, а затем извлечь путь ключа из @{ $entry->[0] }
для каждой записи.Он работает независимо от глубины структуры данных и даже если конечные узлы не встречаются на одной и той же глубине.Однако требуется немного расширения для работы со структурами, которые не являются чисто хеш-рефами и простыми скалярами.