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

I have two array of hashes. I'd like to compare the two arrays and decipher based on a particular hash key in each of the hashes
1) The common keys between the arrays
2) If one array contains hash key that is not present in the other array
The hashes (there may be two or more) in each of the arrays are the same structure
e.g.
@array1 = { { hour => "1", minute => "30", flag => "cmd1" }, { hour => "1", minute => "30", flag => "cmd2" }, { hour => "1", minute => "30", flag => "cmd3" } }; @array2 = { { hour => "1", minute => "30", flag => "cmd1" }, { hour => "1", minute => "30", flag => "cmd2" }, { hour => "1", minute => "30", flag => "cmd3" }, { hour => "1", minute => "30", flag => "cmd4" } };
In this example if I wished to use the flag key for comparison purposes between the arrays. How do I do this ?
i.e. flag => "cmd4" only exists in @array2
This is a scaled down version of a real issue I have. Any help appreciated.

Replies are listed 'Best First'.
Re: compare an array of hashes
by inman (Curate) on Mar 09, 2006 at 16:38 UTC
    Functions such as each_array and pairwise from List::MoreUtils will allow you to iterate over two lists at a time and process them. This assumes that your lists are similar and you are just trying to get different items.

    If your data is key driven then you can use a hash to find the unique keys and then grep them from the list.

    my @wanted; my %keys; $keys{$_->{flag}}++ foreach (@array1, @array2); my @unique = grep {$keys{$_->{flag}} == 1} @array2; print Dumper(@unique);
      This is exactly what I was looking for. How do I get a list of the keys that are common to both ?
Re: compare an array of hashes
by leocharre (Priest) on Mar 09, 2006 at 16:58 UTC

    I'm going to solve the problem by creating a rudimentary "digest" of each anonymous hash in each array. Hash %structures will hold the "digests" as keys to anonymous arrays that will hold where the "digest" came from, what array, and what position.

    This will be ugly- the output will be mainly for you- it wouldn't be so useful for code, I suppose- but I really have no idea what you expect as output- it's too vague.

    #!/usr/bin/perl -w use strict; use Data::Dumper; my @array1 = ( { hour => "1", minute => "30", flag => "cmd1" }, { hour => "1", minute => "30", flag => "cmd2" }, { hour => "1", minute => "30", flag => "cmd3" } ); my @array2 = ( { hour => "1", minute => "30", flag => "cmd1" }, { hour => "1", minute => "30", flag => "cmd2" }, { hour => "1", minute => "30", flag => "cmd3" }, { iamdifferent =>'because', hour => "1", minute => "30", flag => "cmd4" }, { iamdifferent =>'because', hour => "1", minute => "40", flag => "cmd6" }, { iamdifferent =>'because', hour => "1", minute => "40", flag => "cmd6", minute => "40" }, { a =>'because', b => "1", c => "40", d => "cmd6", minute => "40" } ); # this will hold my hash "digests" as keys to lists of # what array and position it happened in. my %structures=(); # the arrays with anon hashes we will analize my @arrays=(\@array1, \@array2); my $which_array=0; for (@arrays){ my $a=$_; my $anon_hash_position_in_array=0; for (@{$a}){ my $structure; for my $k(sort (keys %{$_})){ $structure.=":$k:"; } my $val= "array$which_array"."_position$anon_hash_position_in_ +array"; push @{$structures{$structure}}, $val; $anon_hash_position_in_array++; } $which_array++; } print Dumper(\%structures); exit;

    Output:

    $VAR1 = { ':flag::hour::minute:' => [ 'array0_position0', 'array0_position1', 'array0_position2', 'array1_position0', 'array1_position1', 'array1_position2' ], ':flag::hour::iamdifferent::minute:' => [ 'array1_position3' +, 'array1_position4' +, 'array1_position5' ], ':a::b::c::d::minute:' => [ 'array1_position6' ] };
Re: compare an array of hashes
by ayrnieu (Beadle) on Mar 09, 2006 at 17:37 UTC
    The quickest solution would make use of accelerated, unsorted invocations of List::Compare