0

I've got the following structure (in reality, it is much bigger):

$param_hash = {
          'param1' => [0, 1],
          'param2' => [0, 1, 2],
          'param3' => 0,
        };

And I'd like to print all the possible combinations of different parameters in the line, like this:

param1='0' param2='0' param3='0'
param1='0' param2='1' param3='0'
param1='0' param2='2' param3='0'
...

I understand that an iteration is needed (like this one), but I just cannot get it to work. How should I do this?
Or maybe I just should use another structure for storing parameters values scope?

Community
  • 1
  • 1
evgeny9
  • 1,381
  • 3
  • 17
  • 31
  • what have you tried? you should do a foreach through the hash then foreach through the array. – scrappedcola Aug 02 '12 at 17:57
  • @scrappedcola: I tried such two foreach cycles inside of each other, but then I just get a list like `param1='0' param1='1' param1='2' param2='0' ...` Then I tried to iterate them, but ended up in an endless iteration. – evgeny9 Aug 02 '12 at 18:03
  • is param_hash supposed to be a hash or a ref? – scrappedcola Aug 02 '12 at 18:07
  • @scrappedcola: A reference (but, in fact, as I understand, it does not matter for the iteration algorithm). – evgeny9 Aug 02 '12 at 18:11

3 Answers3

1

first you would have to find the longest possible array ref in the hash keys, the iterate like this

for my $value (0..$maxValue) {
    foreach my $key (sort keys %$param_hash) {

        unless (ref($param_hash->{$key}) eq 'ARRAY') {
            $param_hash->{$key} = [$param_hash->{$key}];
        }

        print "$key=", $#{$param_hash->{$key}} >= $value ? $param_hash->{$key}->[$value] : 0;
        print ' ';
    }
    print "\n";
}

where maxValue is the longest possible array ref, in this case 2. That will format it the way you described in your question.

John Corbett
  • 1,595
  • 10
  • 19
  • Thank you, but it doesn't show all the combinations and tells about `Use of uninitialized value` when trying to print an array shorter than maxValue. Besides, shouldn't it be '2' for the example? – evgeny9 Aug 02 '12 at 18:17
  • Unfortunately, an error again: `param1=0 param2=0 param3=0 param1=1 param2=1 param3=1 Use of uninitialized value in print` – evgeny9 Aug 02 '12 at 18:31
  • ok, I got this for real now... I actually ran this code and it works. Sorry about the confusion... – John Corbett Aug 02 '12 at 18:40
  • Thank you for the attempts, but it still outputs `param1=0 param2=0 param3=0 / param1=1 param2=1 param3=0 / param1=0 param2=2 param3=0`. So, the output consists of 3 combinations and I want to get them all, i.e. 2*3*1=6. – evgeny9 Aug 03 '12 at 09:47
  • then add a variable `my $product = 1` inside the outer loop, take out the prints, change the first print to `my $key =` and then do `$product *= $key`, if I'm understanding you correctly. – John Corbett Aug 03 '12 at 13:38
  • Corbrett: I'm also a bit confused right now - it turned out to be a very puzzled implementation. I think I chose the wrong soring structure in the first place, so I'll try to change it. Thank you for the help! – evgeny9 Aug 03 '12 at 14:05
1
foreach my $key (keys %$param_hash){
    if(ref $param_hash->{$key} eq 'ARRAY'){
        foreach my $value (@{$param_hash->{$key}}){
            print "$key = $ value ";
        }
    }
        else {
            print "$key = $param_hash->{$key} ";
        }
    print "\n"
    }
Error
  • 111
  • 3
  • It outputs not all the combinations for different parameters, but all parameter values for every parameter: `param1='0' param1='1' param1='2' \n param2='0' ...` – evgeny9 Aug 02 '12 at 18:21
1

This solution assumes the parameter ordering doesn't matter provided all cases are covered. I think CPAN has some ordered hashing if it's important to your problem.

use strict;

my %KNOBS = (ARG1=>[1,2,3],
             ARG2=>['a','b'],
             ARG3=>['41:R']);

my %indicies;
foreach my $keys (keys %KNOBS)
{
  $indicies{$keys}=0;
}

my @orderedkeys = (keys %KNOBS);

printknobs();
while(incrimentindicies())
{
  printknobs();
}

sub printknobs
{
  foreach (@orderedkeys)
  {
    print "-$_ $KNOBS{$_}[$indicies{$_}] "; #num elements in array $key of %knob
  }
  print "\n";
}

sub incrimentindicies
{
  foreach (@orderedkeys)
  {
    if( $indicies{$_} + 1 < @{$KNOBS{$_}})
    {
      $indicies{$_} = $indicies{$_} + 1;
      return 1;
    }else{
      $indicies{$_} = 0;
    }
  }
  return 0;
}

Output:

-ARG2 a -ARG3 41:R -ARG1 1
-ARG2 b -ARG3 41:R -ARG1 1
-ARG2 a -ARG3 41:R -ARG1 2
-ARG2 b -ARG3 41:R -ARG1 2
-ARG2 a -ARG3 41:R -ARG1 3
-ARG2 b -ARG3 41:R -ARG1 3

@orderedkeys ensures that the changes in the ordering of %indicies won't matter between calls to incrimentindicies.

OBoud
  • 119
  • 6