Home > Blockchain >  Merging perl array which contains hashes in it
Merging perl array which contains hashes in it

Time:10-08

I am trying to do Merging in perl where array which contains hashes in it, I am trying to not merge duplicate elements(via uniq function) in an array while merging.

use strict;
use Hash::Merge qw/merge/;
use List::MoreUtils qw/uniq/;
use Data::Dumper;

my $h1 = { name1    => [ {
                           sport  => "tennis",
                           country => "us",
                          },
                          {
                           sport => "soccer",
                           country => "brazil",
                          },
                          {
                           sport  => "cricket",
                           country => "india"
                          },
                        ]
        };

my $h2 = { name1 => [   {
                           sport => "soccer",
                           country => "brazil",
                          },

                        {
                           sport  => "boxing",
                           country => "china"
                         }
                          ],

        };

Hash::Merge::specify_behavior(  {
                        SCALAR => {
                                SCALAR => sub { $_[1] },
                                ARRAY  => sub { [ $_[0], @{$_[1]} ] },
                                HASH   => sub { $_[1] },
                        },
                        ARRAY => {
                                SCALAR => sub { $_[1] },
                                ARRAY  => sub { [ uniq( @{$_[0]}, @{$_[1]}) ] },
                                HASH   => sub { $_[1] },
                        },
                        HASH => {
                                SCALAR => sub { $_[1] },
                                ARRAY  => sub { [ values %{$_[0]}, @{$_[1]} ] },
                                HASH   => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
                        },
                },
                'setting merge',
        );

my $h_data = merge($h1, $h2);

print Dumper $h_data;

Output:-

$VAR1 = {
      'name1' => [
                   {
                     'country' => 'us',
                     'sport' => 'tennis'
                   },
                   {
                     'country' => 'brazil',
                     'sport' => 'soccer'
                   },
                   {
                     'sport' => 'cricket',
                     'country' => 'india'
                   },
                   {
                     'country' => 'brazil',
                     'sport' => 'soccer'
                   },
                   {
                     'country' => 'china',
                     'sport' => 'boxing'
                   }
                 ]
    };

When I try to merge with custom merge method, I am not able to eliminate duplicate elements ({ sport => "soccer" country => "brazil" }). Seems like reason is because of elements in hash format. Do we have any easy way using custom merge technique to achieve it. Thanks!

CodePudding user response:

You can try to flatten the sub hashes in the arrays in order to be able to apply uniq to them. Then expand the sub hashes back after removing the duplicates. For example:

Hash::Merge::specify_behavior(
  {
    SCALAR => {
        SCALAR => sub { $_[1] },
        ARRAY  => sub { [ $_[0], @{$_[1]} ] },
        HASH   => sub { $_[1] },
    },
    ARRAY => {
        SCALAR => sub { $_[1] },
        ARRAY  => sub { my_array_merge( $_[0], $_[1] ) },
        HASH   => sub { $_[1] },
    },
    HASH => {
        SCALAR => sub { $_[1] },
        ARRAY  => sub { [ values %{$_[0]}, @{$_[1]} ] },
        HASH   => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
    },
  },
  'setting merge',
);


my $h_data = merge($h1, $h2);

print Dumper $h_data;


sub flatten_array_of_hash {
    my ( $ar ) = @_;

    my @flat;
    for my $hash (@$ar) {
        die "Not hash ref" if !(ref $hash eq "HASH");
        my @ar;
        for my $key (sort keys %$hash) {
            push @ar, join $;, $key, $hash->{$key};
        }
        push @flat, join $;, @ar;
    }
    return \@flat;
}

sub my_array_merge {
    my ($a1, $a2) = @_;

    my $f1 = flatten_array_of_hash( $a1 );
    my $f2 = flatten_array_of_hash( $a2 );
    my @flat = uniq @$f1, @$f2;
    my @result;
    for my $item (@flat) {
        my %hash = split $;, $item;
        push @result, \%hash;
    }
    return \@result;
}
  • Related