evgeny9
evgeny9

Reputation: 1441

How to iterate through hash of arrays in Perl?

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?

Upvotes: 0

Views: 3134

Answers (3)

OBoud
OBoud

Reputation: 119

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.

Upvotes: 1

John Corbett
John Corbett

Reputation: 1615

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.

Upvotes: 1

Error
Error

Reputation: 111

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"
    }

Upvotes: 1

Related Questions