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

Hi there Monks!

I am trying to merge these two arrays only if the acc matches, can any one tell me what could be the best way to do this?
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $data1 = [ { 'NAME' => '1PAUL DY', 'DATE' => '12009-05-05', 'NUMBER' => '100001', 'ACC' => '1A1A', }, { 'NAME' => '2PAUL DY', 'DATE' => '2011-01-05', 'NUMBER' => '200331', 'ACC' => '2A3B', }, { 'NAME' => '4PAUL DY', 'DATE' => '42011-01-05', 'NUMBER' => '4200331', 'ACC' => '6A4B', }, ]; my $data2 = [ { 'EXT1' => '1b', 'EXT2' => '12b', 'EXT3' => '13b', 'EXT4' => '14d', 'ACC' => '1A1A', }, { 'EXT1' => '2b', 'EXT2' => '2b', 'EXT3' => '2b', 'EXT4' => '2d', 'ACC' => '2A3B', }, { 'EXT1X' => '4b', 'EXT2X' => '4b', 'EXT3X' => '4b', 'EXT4X' => '4d', 'ACC' => '4A4B', }, ]; # Merge all the data my @all_data; foreach my $one_data ( @{ $data1 } ) { my $sec_data = shift @{ $data2}; push @all_data, { %{ $one_data }, %{ $sec_data } }; } print Dumper \@all_data;

Thanks for the help!

Replies are listed 'Best First'.
Re: Merging Data into one array
by choroba (Cardinal) on Nov 30, 2015 at 20:25 UTC
    You can transform your data into two hashes, ACC being their keys. Then you can easily iterate over the keys of one hash and merge with the corresponding value from the second hash if the key exists there:
    my @transformed = map +{ map { my $k = delete $_->{ACC}; $k => $_; } @$_ }, $data1, $data2; my @merged; for my $key (keys %{ $transformed[0] }) { if (exists $transformed[1]{$key}) { push @merged, { ACC => $key, %{ $transformed[0]{$key} }, %{ $transformed[1]{$key} } }; } } print Dumper \@merged;
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Merging Data into one array
by toolic (Bishop) on Nov 30, 2015 at 20:20 UTC
    Change:
    push @all_data, { %{ $one_data }, %{ $sec_data } };

    to:

    push @all_data, { %{ $one_data }, %{ $sec_data } } if $one_data->{ +ACC} eq $sec_data->{ACC};

    Output:

    $VAR1 = [ { 'ACC' => '1A1A', 'DATE' => '12009-05-05', 'EXT1' => '1b', 'EXT2' => '12b', 'EXT3' => '13b', 'EXT4' => '14d', 'NAME' => '1PAUL DY', 'NUMBER' => '100001' }, { 'ACC' => '2A3B', 'DATE' => '2011-01-05', 'EXT1' => '2b', 'EXT2' => '2b', 'EXT3' => '2b', 'EXT4' => '2d', 'NAME' => '2PAUL DY', 'NUMBER' => '200331' } ];
Re: Merging Data into one array
by BrowserUk (Patriarch) on Nov 30, 2015 at 20:23 UTC

    Like this?:

    #!/usr/bin/perl use strict; use warnings; use Data::Dump qw[ pp ]; my $data1 = [ { 'NAME' => '1PAUL DY', 'DATE' => '12009-05-05', 'NUMBER' => '1000 +01', 'ACC' => '1A1A', }, { 'NAME' => '2PAUL DY', 'DATE' => '2011-01-05', 'NUMBER' => '20033 +1', 'ACC' => '2A3B', }, { 'NAME' => '4PAUL DY', 'DATE' => '42011-01-05', 'NUMBER' => '4200 +331', 'ACC' => '6A4B', }, ]; my $data2 = [ { 'EXT1' => '1b', 'EXT2' => '12b', 'EXT3' => '13b', 'EXT4' => '14d' +, 'ACC' => '1A1A', }, { 'EXT1' => '2b', 'EXT2' => '2b', 'EXT3' => '2b', 'EXT4' => '2d', ' +ACC' => '2A3B', }, { 'EXT1X' => '4b', 'EXT2X' => '4b', 'EXT3X' => '4b', 'EXT4X' => '4d +', 'ACC' => '4A4B', }, ]; for my $i ( 0 .. $#{ $data1 } ) { if( $data1->[ $i ]{ ACC } eq $data2->[ $i ]{ ACC } ) { $data1->[ $i ]{ $_ } = $data2->[ $i ]{ $_ } for keys %{ $data2 +->[ $i ] } } } pp $data1; __END__ C:\test>1148951.pl [ { ACC => "1A1A", DATE => 12009-05-05, EXT1 => "1b", EXT2 => "12b", EXT3 => "13b", EXT4 => "14d", NAME => "1PAUL DY", NUMBER => 100001, }, { ACC => "2A3B", DATE => 2011-01-05, EXT1 => "2b", EXT2 => "2b", EXT3 => "2b", EXT4 => "2d", NAME => "2PAUL DY", NUMBER => 200331, }, { ACC => "6A4B", DATE => 42011-01-05, NAME => "4PAUL DY", NUMBER => +4200331 }, ]

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Merging Data into one array
by stevieb (Canon) on Nov 30, 2015 at 20:23 UTC

    You don't specify if all your hashes will always be in the same order in each array ref. This example code below believes that they will be (which was kind of apparent in your code, but one never knows):

    for (0..$#$data1){ if ($data1->[$_]{ACC} eq $data2->[$_]{ACC}){ push @all, { %{ $data1->[$_] }, %{ $data2->[$_] } }; } }
      That's a good point, I don't know if they will be all in the same order.

        List::MoreUtils to the rescue here... we'll generate a new array with every ACC in $data2 (ordered), then we'll iterate over $data1, using first_index() to search for its ACC in the new array created above. That'll return to $index the element location from the new array, which we then use to extract the full hash from the proper location (index) of the full $data2. Make sense? ;)

        use List::MoreUtils qw(first_index); my @all; my @data2_acc_list; push @data2_acc_list, $data2->[$_]{ACC} for 0..$#$data2; for (0..$#$data1){ my $acc = $data1->[$_]{ACC}; my $index = first_index { /$acc/ } @data2_acc_list; if ($index >= 0){ push @all, { %{ $data1->[$_] }, %{ $data2->[$index] } }; } } print Dumper \@all;

        Note that if $data2 has matching ACC values, things will probably be squirly, as only the first one will be hit. I also had to read the docs on first_index()... it returns -1 if the element can't be found, and I was checking for truth, not explicitly for zero or greater.

Re: Merging Data into one array
by kcott (Archbishop) on Dec 01, 2015 at 07:18 UTC

    Here's a solution with just map and grep:

    #!/usr/bin/env perl use strict; use warnings; my $data1 = [ { 'NAME' => '1PAUL DY', 'DATE' => '12009-05-05', 'NUMBER' => '1000 +01', 'ACC' => '1A1A', }, { 'NAME' => '2PAUL DY', 'DATE' => '2011-01-05', 'NUMBER' => '20033 +1', 'ACC' => '2A3B', }, { 'NAME' => '4PAUL DY', 'DATE' => '42011-01-05', 'NUMBER' => '4200 +331', 'ACC' => '6A4B', }, ]; my $data2 = [ { 'EXT1' => '1b', 'EXT2' => '12b', 'EXT3' => '13b', 'EXT4' => '14 +d', 'ACC' => '1A1A', }, { 'EXT1' => '2b', 'EXT2' => '2b', 'EXT3' => '2b', 'EXT4' => '2d', + 'ACC' => '2A3B', }, { 'EXT1X' => '4b', 'EXT2X' => '4b', 'EXT3X' => '4b', 'EXT4X' => ' +4d', 'ACC' => '4A4B', }, ]; my @merged = map { { %{$data1->[$_]}, %{$data2->[$_]} } } grep { $data1->[$_]{ACC} eq $data2->[$_]{ACC} } 0 .. $#$data1; # Check results use Data::Dump; dd \@merged;

    Output:

    $ pm_1148951_merge_arrays.pl [ { ACC => "1A1A", DATE => "12009-05-05", EXT1 => "1b", EXT2 => "12b", EXT3 => "13b", EXT4 => "14d", NAME => "1PAUL DY", NUMBER => 100001, }, { ACC => "2A3B", DATE => "2011-01-05", EXT1 => "2b", EXT2 => "2b", EXT3 => "2b", EXT4 => "2d", NAME => "2PAUL DY", NUMBER => 200331, }, ]

    — Ken

      This is an exceptionally fragile solution. It assumes not only that each array contains the same number of records, but that every related record is in the same place in each array.

        I make a point of clearly stating any assumptions I make. I have made no assumptions here.

        The OP wrote "I am trying to merge these two arrays ...". My solution merges the two arrays provided by the OP.

        — Ken