newbio has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,
my @array=(['john','tom','peter'],['rose','teak'],['car','truck','jeep +'],['trees','plants'],['good','bad','ugly']); my @arrayindex=(3,1); my %hash=(); foreach my $i (@{$array[$arrayindex[0]]}) { foreach my $j (@{$array[$arrayindex[1]]}) { $hash{"$i $j"}=1; } } foreach my $i (keys %hash) { print "$i=>$hash{$i}\n"; } The output of the program is a hash whose keys represent all possible +combination of values: trees rose=>1; trees teak=>1; plants rose=>1; plants teak=>1;
However, I do not know how to handle variable number of elements in @arrayindex, because the above code is rigid and can only work for exactly two elements in @arrayindex (such as @arrayindex=(3,1)). I want the code to be generic so that it can handle any number of elements in @arrayindex, such as, @arrayindex=(3,0,1), @arrayindex=(3,1), @arrayindex=(4,2,1,5), or @arrayindex=(2) etc. Please advise how this can be done. My thinking here was to create the number of foreach loops dynamically, however, don't know if that is even possible. Thank you guys, Raj

Replies are listed 'Best First'.
Re: Advice on loops
by merlyn (Sage) on May 03, 2007 at 15:27 UTC
    Just use a recursive routine to drill down. Witness:
    my @array=(['john','tom','peter'],['rose','teak'],['car','truck','jeep +'],['trees','plants'],['good','bad','ugly']); my @arrayindex=(3,1); my @wanted = @array[@arrayindex]; # get slice show(@wanted); sub show { if (ref @_[0]) { # still recursing for (@{+shift}) { show(@_, $_); } } else { # end case print "@_\n"; # do what you want with the results here } }
    This prints:
    trees rose trees teak plants rose plants teak
Re: Advice on loops
by liverpole (Monsignor) on May 03, 2007 at 16:15 UTC
    Hi newbio,

        ...to create the number of foreach loops dynamically, however, don't know if that is even possible

    Of course it's possible -- this is Perl! :-)

    Here's a rewrite of your program using a subroutine dynamic_assign, which I think does what you want:

    #!/usr/bin/perl -w # Always use strict & warnings! use strict; use warnings; # User-data my @array = ( ['john','tom','peter'], ['rose','teak'], ['car','truck','jeep'], ['trees','plants'], ['good','bad','ugly'], ); my @arrayindex = (4, 2, 1); my %hash = (); # Main program # # The "hard-wired" (ie. original) way to do it # # foreach my $i (@{$array[$arrayindex[0]]}) { # foreach my $j (@{$array[$arrayindex[1]]}) { # $hash{"$i $j"}=1; # } # } # The "new" way (using a recursive subroutine) dynamic_assign(\@arrayindex, \@array, \%hash); foreach my $i (keys %hash) { print "$i=>$hash{$i}\n"; } # Subroutines # # Inputs # $1 ... a pointer to a list of indices (eg. [ 4, 2, 1, 5]) # $2 ... a pointer to a list of lists (see @array in the main progr +am) # $3 ... a pointer to a hash # # $4 ... (when recursing) the current index into the list of indice +s # $5 ... (when recursing) the accumulated key # # Results: # Assigns each final key of the hash to 1. # sub dynamic_assign { my ($pindices, $parray, $phash, $idx, $key) = @_; # The 1st time -- initialize index and key defined($key) or ($idx, $key) = (0, ""); if ($idx < @$pindices) { # Use each value of the selected array my $index = $pindices->[$idx]; foreach my $value (@{$parray->[$index]}) { my $newkey = $key? "$key $value": $value; # Here comes the recursion... dynamic_assign($pindices, $parray, $phash, $idx+1, $newkey +); } } else { # Final assignment $phash->{$key} = 1; } }

    It lets you specify what indices you want in @arrayindex, and then calls the subroutine dynamic_assign which takes care of the rest.  The "magic" part is that dynamic_assign calls itself recursively, so that every necessary hash key is generated.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
      You Monks are absolutely terrific. Its because of your support that my interest in Perl has kept afloat..:). As a small token of appreciation, I would like to donate some money to the forum. Please advice me if this is possible (through paypal?). Thank you all. Raj

        PayPal is certainly possible.

        Offering Plate may be of interest to you.

Re: Advice on loops (A::L::NestedLoops)
by tye (Sage) on May 03, 2007 at 17:48 UTC
Re: Advice on loops
by parv (Parson) on May 03, 2007 at 22:22 UTC
    What do you want to happen when @arrayindex has only one element? Given your original hardcoded code, there will be no enteries in the hash.