Question

$description is Input from a yaml file of format

main_key:
 -
  key1:value2
  key2:value2
 -
  key1:value1
  key2:value2

Basically that is a hash of array of hashes.

I input $description and process the inner hash as follows:

while (  my ( $mod, $defined )  = each %{ $description } ) {
  my $index = 0;
  foreach ( @{ $defined } ) {
    while ( my ( $key, $value )  = each %{ $_ } ) {
         process ( $key, $mod, $description, $index );
    }
  $index = $index + 1;
  }
}

When certain 'keyword' is used as a key I replace add more key,value pairs to the inner hash function1() and function2() return a hash pointer.

sub process {
      my ( $key, $mod, $description, $index ) = @_; 
      my $parameters;
      if ( $key eq 'keyword' ) {
             $parameters = function1( );
      }
      else {
             $parameters = function2( );
      }
      $description->{$mod}[$index] = { %$parameters, %{$description->{$mod}[$index]} };
}

The issue here is that "while ( my ( $key, $value ) = each %{ $_ } )" in the main code runs forever, using the same key and value over and over again.

No correct solution

OTHER TIPS

Yeah. Don't do that.

Never modify a hash while looping over it. From perldoc -f each:

If you add or delete a hash's elements while iterating over it, entries may be skipped or duplicated--so don't do that.

The general pattern is to build up the list of modifications, and then make them after the end of the loop. You can, of course, embed that sequence in an outer loop that iterates over the hash until there are no more modifications that need to be made.

This refactoring of your code works fine. I have rewritten process to do all that is necessary for the innermost hashes. I have named these $item as I don't know what they are supposed to represent. Please amend this to something more descriptive.

There never was any reason to pass all those parameters, as the values of $description, $mod, and $index were only used to locate the hash in question using $description->{$mod}[$index] so it may as well have been passed directly as a reference, which is what I do. In addition, because process now loops over the array contents there is no need to pass $key either, so the subroutine now has just one parameter.

Each element of $item is examined, and the new hash of data to be added for that element is obtained from function1 or function2 as appropriate and pushed onto @params instead of being inserted straight away.

Once all the new values have been established, they are all added into $item and the process is complete.

for my $defined (values %$description) {
  process($_) for @$defined;
}

sub process {
  my ($item) = @_;
  my @params;

  for my $key (keys %$item) {
    push @params, $key eq 'keyword' ? function1() : function2();
  }

  for my $params (@params) {
    @{$item}{keys %$params} = values %{$params};
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top