1

I have a %parallel_hash with indexed key names 0-2:

%parallel_hash
(function_name_0 => "sharp_mpi_steps::run_mpirun",
params_name_0    => ("reporter","xml_obj",$hash{value}),
function_name_1  => "sharp_mpi_steps::run_mpirun",
params_name_1    => ("reporter","xml_obj",$hash{value}),
(function_name_2 => "sharp_mpi_steps::run_mpirun",
params_name_2    => ("reporter","xml_obj",$hash{value})

I would like to update the $hash{value} content with an indexed text. To each $hash{value} inside params_name_$i, simply add another key and value: reporter_message => "process_$i"

my code is:

package delete;
use strict;
use warnings FATAL => 'all';

my %parallel_hash;
my %hash_mpi;

$hash_mpi{value}->{bind_to} = "none";
for (my $i=0;$i<=2;$i++)
{
    my %hash;
    $hash{value} = $hash_mpi{value};
    $parallel_hash{"function_name_$i"}  = "sharp_mpi_steps::run_mpirun";
    @{$parallel_hash{"params_name_$i"}} = ("reporter","xml_obj",$hash{value});
    $parallel_hash{"params_name_$i"}->[2]->{reporter_message} = "process_$i";
}

print ("Done");
1;

I would like to get:

%parallel_hash
 'function_name_0' = "sharp_mpi_steps::run_mpirun"
 'params_name_0' =
 [0] = "reporter"
 [1] = "xml_obj"
 [2] =
    'bind_to' = "none"
    'reporter_message" = "process_0"
 'function_name_1' = "sharp_mpi_steps::run_mpirun"
 'params_name_1' =
 [0] = "reporter"
 [1] = "xml_obj"
 [2] =
    'bind_to' = "none"
    'reporter_message" = "process_1"
 'function_name_2' = "sharp_mpi_steps::run_mpirun"
 'params_name_2' =
 [0] = "reporter"
 [1] = "xml_obj"
 [2] =
    'bind_to' = "none"
    'reporter_message" = "process_2"

The problem is that after the "reporter_message" key is added, it updates all the previous "params_name_$i" as well:

%parallel_hash
 'function_name_0' = "sharp_mpi_steps::run_mpirun"
 'params_name_0' =
 [0] = "reporter"
 [1] = "xml_obj"
 [2] =
    'bind_to' = "none"
    'reporter_message" = "process_2"
 'function_name_1' = "sharp_mpi_steps::run_mpirun"
 'params_name_1' =
 [0] = "reporter"
 [1] = "xml_obj"
 [2] =
    'bind_to' = "none"
    'reporter_message" = "process_2"
 'function_name_2' = "sharp_mpi_steps::run_mpirun"
 'params_name_2' =
 [0] = "reporter"
 [1] = "xml_obj"
 [2] =
    'bind_to' = "none"
    'reporter_message" = "process_2"

How can I avoid this updating?

brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • 1
    $hash{value} = $hash_mpi{value}` does not do a deep copy. https://stackoverflow.com/questions/7083453/copying-a-hashref-in-perl – jhnc Jun 05 '22 at 22:04
  • 1
    Does this answer your question? [Copying a hashref in Perl](https://stackoverflow.com/questions/7083453/copying-a-hashref-in-perl) – jhnc Jun 05 '22 at 22:04
  • Copying references around, instead of using "deep copy," does seem to be a problem, but you also overwrite the element at index 2 of `@{$parallel_hash{"params_name_$i"}}` (instead of adding a key) ? There are other problems as well. (Why do you call the package `delete` -- it's a reserved word in Perl.) Can you show us the data structure you have, and the one you want to build? I mean in correct Perl (or `Dumper` output of it). – zdim Jun 05 '22 at 22:33

1 Answers1

1
my %hash_mpi;
$hash_mpi{value}->{bind_to} = "none";

my %hash;
$hash{value} = $hash_mpi{value};

@{$parallel_hash{"params_name_$i"}} = ("reporter","xml_obj",$hash{value});

is a weird way of doing

my $value = { bind_to => "none" };

$parallel_hash{ "params_name_$i" } = [ "reporter", "xml_obj", $value ];

You're adding a reference to same hash to every array.

You want

my %parallel_hash;
for my $i ( 0 .. 2 ) {
    $parallel_hash{ "function_name_$i" }  = "sharp_mpi_steps::run_mpirun";

    my %hash = (                              # Create a new hash.
       bind_to          => "none",
       reporter_message => "process_$i",
    );
    $parallel_hash{ "params_name_$i" } = [
       "reporter",
       "xml_obj",
       \%hash,                                # Create a reference to that hash.
    ];
}

{} does those two things at once.

my %parallel_hash;
for my $i ( 0 .. 2 ) {
    $parallel_hash{ "function_name_$i" }  = "sharp_mpi_steps::run_mpirun";

    $parallel_hash{ "params_name_$i" } = [
       "reporter",
       "xml_obj",
       {
          bind_to          => "none",
          reporter_message => "process_$i",
       }
    ];
}

That's a very weird data structure, by the way. Using an array would make more sense.

my @data;
for my $i ( 0 .. 2 ) {
    push @data, { 
       function => "sharp_mpi_steps::run_mpirun",
       params => [
          "reporter",
          "xml_obj",
          {
             bind_to          => "none",
             reporter_message => "process_$i",
          }
       ],
    };
}
ikegami
  • 367,544
  • 15
  • 269
  • 518