There are several issues with your approach that you need to find out. First, what happens if there are two leaf nodes with the same key? The second entered the first, the second is ignored, should the output contain a list of them? Here is one approach. First, we build a flat list of key value pairs using a recursive function to process other hash depths:
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";
The fix may be something like this, which will create a hash of the refs array containing all the values:
sub merge { my %out; while (@_) { my ($key, $value) = splice @_, 0, 2; push @{ $out{$key} }, $value } %out } my %better_flat = merge flatten \%data;
In production code, it would be faster to pass links between functions, but I omitted this for clarity.
Eric Strom
source share