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

Hi monks,
I have been hacking away at getting a solution to the below problem but just cant seem to get it to work and would appreciate some help, please!

Below is a sample hash structure that I am working with.

I am trying to compare all the values in the 'myStr' of each hash key ID (ID1, ID2, ID3) to the 'yourStr' values of other ID keys and simply print the 'ID' or 'description' of matches.

Sort of like:

Loop through the hash keys i.e. ID1, ID2, ID3
foreach ID1
then check if the 'myStr' in ID1 matches the 'yourStr' ID2, ID3, etc..

Also, please note that the 'yourStr' values are in an array in the hash

Any ideas or help would be greatly appreciated!

$VAR1 = { 'ID1' => { 'myStr' => 'hello', 'description' => 'Description 1', 'yourStr' => [ 'goodbye', 'where' ] }, 'ID2' => { 'myStr' => 'good', 'description' => 'Description 2', 'yourStr' => [ 'hello', ] }, 'ID3' => { 'myStr' => 'testvar', 'description' => 'Description 2', 'yourStr' => [ 'hello', 'good' ] }, };

Replies are listed 'Best First'.
Re: Comparing values in same hash?
by Marshall (Canon) on Jul 22, 2011 at 16:58 UTC
    This is just a simple nested foreach loop. outer loop iterates over all id's. inner loop iterates over all id's except the current id (skips itself which may or may not be part of the requirements?). Note: grep is used in a scalar context which is the number of matches.
    #!/usr/bin/perl -w use strict; my %hash= ( 'ID1' => { 'myStr' => 'hello', 'description' => 'Description 1', 'yourStr' => [ 'goodbye', 'where' ] }, 'ID2' => { 'myStr' => 'good', 'description' => 'Description 2', 'yourStr' => [ 'hello', ] }, 'ID3' => { 'myStr' => 'testvar', 'description' => 'Description 2', 'yourStr' => [ 'hello', 'good' ] }, ); foreach my $id (keys %hash) { my $mystr = $hash{$id}{myStr}; foreach my $compareid (grep{$_ ne $id}keys %hash) { if (grep{ $_ eq $mystr} @{$hash{$compareid}{yourStr}}) { print "$id myStr=$mystr found in $compareid yourStr=@{$hash +{$compareid}{yourStr}}\n"; } } } __END__ ID1 myStr=hello found in ID3 yourStr=hello good ID1 myStr=hello found in ID2 yourStr=hello ID2 myStr=good found in ID3 yourStr=hello good
      Thanks, this is a simple approach that works. I tried a nested foreach loop but my results kept printing the wrong information. Adding the grep in works great.
Re: Comparing values in same hash?
by Not_a_Number (Prior) on Jul 22, 2011 at 17:59 UTC

    Here's my solution, probably a little more complex than Marshall's above.

    It does two passes over the hash. In the first pass, it builds a HoA where the keys are the all the words from 'yourStr' and the values are arrays holding the IDs concerned, which ends up looking like this:

    good => [ 'ID3' ], hello => [ 'ID1', 'ID3', 'ID2' ], goodbye => [ 'ID1' ], where => [ 'ID1' ]

    On the second pass, it checks if the value of 'myStr' is in the HoA, and prints out any matches, excluding 'internal' matches (ie if for the same ID 'hello' were to appear in both 'myStr' and 'yourStr').

    use strict; use warnings; my $h = { ID1 => { myStr => 'hello', description => 'Description 1', yourStr => [ 'goodbye', 'where', 'hello'] }, ID2 => { myStr => 'good', description => 'Description 2', yourStr => [ 'hello', ] }, ID3 => { myStr => 'testvar', description => 'Description 2', yourStr => [ 'hello', 'good' ] }, }; my %yourstr; for my $id ( keys %$h ) { for ( @{ $h->{$id}->{yourStr} } ) { push @{ $yourstr{$_} }, $id; } } for my $id ( keys %$h ) { my $mystr = $h->{$id}->{myStr}; if ( $yourstr{$mystr} ) { my @matches = grep { $_ ne $id } @{ $yourstr{$mystr} }; print "'$mystr' in $id matches @matches\n"; } }

    Output:

    'hello' in ID1 matches ID3 ID2 'good' in 1D2 matches ID3
      This is a great solution as well. I will break the code down to understand it further and post any questions. Thank you
Re: Comparing values in same hash?
by Anonymous Monk on Jul 22, 2011 at 20:28 UTC