Here's some code that works for your test data. There's an obvious bug (infinite recursion if there's a loop in your data): I'm sure you can solve that yourself.
$hash{"0"}=["1","2","15"];
$hash{"1"}=["3","4"];
$hash{"2"}=["5","6"];
$hash{"3"}=["7","8"];
sub expand
{
my ($key) = @_;
if (exists $hash{$key})
{
return sort { $a <=> $b } $key, map { expand($_) } @{$ha
+sh{$key}}
}
else
{
return $key
}
}
my @expanded = map {[ expand $_ ]} @{$hash{0}};
use Data::Dumper;
print Dumper(\@expanded);
--Dave
Update: I've just realised that the if (exists ...) check is not needed: if the key doesn't exist, then an empty array will be used, automagically. so the expand function becomes:
sub expand
{
my ($key) = @_;
return sort { $a <=> $b } $key, map { expand($_) } @{$hash{$ke
+y}}
}
Update 2: For efficiency, you probably want to move the sort outside the loop!
Update 3: For the golfers amongst us:
sub e{@_,map{e($_)}@{@hash{@_}}}
print Dumper[map{[sort{$a<=>$b}e$_]}@{$hash{0}}]
| [reply] [d/l] [select] |
I think you mean to assign anonymous arrays and not lists. Other than that, I don't see your pattern. Can you be more explicit about how you decide what fits where?
$hash{0} = [ 1, 2, 15 ];
$hash{1} = [ 3, 4 ];
$hash{2} = [ 5, 6 ];
$hash{3} = [ 7, 8 ];
| [reply] [d/l] |
So with key = "0", we have possible keys of 1, 2, or 15. If it isn't a key, we need to keep the value. If it is a key, we still need to keep the value, but also add in the values of the hash at that key.
Do you see now?
Edited
I almost forgot, the values of the item, if it is a key, also can be keys themselves, and need to be treated in the same way.
| [reply] |
As chromatic said, your initial assignments don't quite work.
You cannot put an array ("3","4) into a scalar $hash{"1"};
instead, you need to use references.
It sounds like you would like to do a recursive descent,
expanding each index into itself as well as its values
in the hash, if any. I'm not quite sure how you can do
that and get exactly the string that you describe, but
the following does something like what you describe.
#!/usr/bin/perl -w
$hash{"0"} = ["1","2","15"];
$hash{"1"} = ["3","4"];
$hash{"2"} = ["5","6"];
$hash{"3"} = ["7","8"];
# Recursively expand a key in the hash into itself and its values.
# Returns a reference to an array of keys and references to arrays.
# Warning: If $hash{$n} contains $n then this expansion won't
# terminate.
sub expand {
my ($key) = @_;
my @result = ( $key ); # Keep the value.
foreach my $subkey ( @{$hash{$key}} ) { # If it's a key, expand
push @result, expand($subkey); # that too and append.
}
return \@result;
}
# Apply the algorithm to find the expanded "0" entry.
$newhash{0} = expand(0) ;
# Pretty print the result as a perl data structure.
use Data::Dumper;
print Dumper( $newhash{0} );
# Like the expand() routine,
# but keep everything at the same depth.
sub expandFlat {
my ($key) = @_;
my @result = ( $key );
foreach my $subkey ( @{$hash{$key}} ) {
push @result, expandFlat($subkey);
}
return @result;
}
# Print out the flattened structure.
print "(". join(",",expandFlat(0)) .")\n";
# Running this and compacting the Data::Dumper output a bit gives
#
# (1)
# As a perl data structure:
# $VAR1 = [ 0, [ '1', [ '3', [ '7' ],
# [ '8' ] ],
# [ '4' ] ],
# [ '2', [ '5' ],
# [ '6' ] ],
# [ '15' ] ];
#
# (2)
# As a flat array
# (0,1,3,7,8,4,2,5,6,15)
#
# which as I said, is pretty much your procedure
# if not quite your outcome.
#
| [reply] [d/l] |
If you run this in a loop, you'll eventually get to a point where all the values are non-keys. But this solution assumes you are not interested in the recursion. It also assumes you want to process every key in the hash and not just "0".
my %newhash;
foreach my $key ( keys( %hash ) ) {
$newhash{$key} = [ map {exists($hash{$_}) ? $hash{$_} : $_;} (valu
+es %hash) ];
}
%hash = %newhash;
| [reply] [d/l] |