I have created following hash of arrays (called $hoa) in my script:
$hoa = {
'Continents' => [
'Continent1',
'Continent2',
'Continent3'
],
'Earth' => [
'Continents'
],
'Continent1' => [
'Country1'
],
'Continent3' => [
'Country3'
],
'Country1' => [
'City1',
'City2'
]
};
I want to convert this into an array of arrays for being consumed in the later part of the script. The array of array should look as below:
$aoa=[
['Earth','Continents','Continent1','Country1','City1'],
['Earth','Continents','Continent1','Country1','City2'],
['Earth','Continents','Continent2'],
['Earth','Continents','Continent3','Country3']
];
I have created the following code to achieve the job but it is not working as expected.
sub CreateArrofArr
{
my $arg={@_};
my $member=$arg->{member};
my $hoa=$arg->{hoa};
my $aoa=[];
if(exists($hoa->{$member}))
{
for(my $i=0; $i<scalar(@{$hoa->{$member}}); $i++)
{
my $elem=@{$hoa->{$member}}->[$i];
my $temp_arr=[];
if(!exists($hoa->{$elem}))
{
push(@{$temp_arr},$member);
push(@{$temp_arr},$elem);
push(@{$aoa},$temp_arr);
}
else
{
push(@{$aoa},@{CreateArrofArr(member=>$elem,hoa=>$hoa)})
}
}
}
return ($aoa);
}
my $aoa=CreateArrofArr(member=>"Earth",hoa=>$hoa);
print Dumper($aoa);
$aoa is returned as follows (which is not what I am expecting):
$VAR1 = [
[
'Country1',
'City1'
],
[
'Country1',
'City2'
],
[
'Continents',
'Continent2'
],
[
'Continent3',
'Country3'
]
];
Please help.
Minimal changes:
sub CreateArrofArr {
my $arg = { @_ };
my $member = $arg->{member};
my $hoa = $arg->{hoa};
my $aoa = [];
if (exists($hoa->{$member})) {
for (my $i=0; $i<scalar(@{$hoa->{$member}}); $i++) {
my $elem = $hoa->{$member}->[$i];
push @{$aoa},
map { [ $member, @$_ ] }
@{ CreateArrofArr( member => $elem, hoa => $hoa ) };
}
} else {
my $temp_arr = [];
push @{$temp_arr}, $member;
push @$aoa, $temp_arr;
}
return $aoa;
}
my $aoa = CreateArrofArr( member => "Earth", hoa => $hoa );
Cleaned up version of the above:
sub flatten {
my ($tree, $current) = @_;
my $node = $tree->{$current};
return [ $current ] if !$node;
return
map { [ $current, @$_ ] }
map { flatten($tree, $_) }
@$node;
}
my @flattened = flatten($tree, 'Earth');
An alternative approach is to pass down the path to the root of the tree than to keep prepending to your paths. This simplifies things a little.
sub flatten {
my $tree = shift;
my $node = $tree->{ $_[-1] };
return [ @_ ] if !$node;
return map { flatten($tree, @_, $_) } @$node;
}
my @flattened = flatten($tree, 'Earth');