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

I am in the middle of writing a script and have gotten stuck on an issue. I've been staring at this bit for so long and have made it so much more complicated than it should be that my brain now refuses to focus on it. It's like a giant mental blind spot. So I thought I'd come here and seek guidance through my darkness.

I have two arrays.
The elements of each array are references to anonymous hashes.
Each hash has 4 key/value pairs.

I'm comparing each hash in the two arrays looking for differences. If any single value in a hash is different I want the entire hash saved anonymously to the element of a new array and the key of the changed value should be "CHANGED."

Here's how I'm going through the arrays and hashes (and bears, Oh my!). (I realize this isn't very efficient. Any pointers how to make it more so would also be appreciated.)

use strict; foreach my $element1 (@array1) { foreach my $element2 (@array2) { foreach my $key (keys %{$element1}) { next if (%{$element1}->{$key} = %{$element2}->{$key}); ## OK Here's where the magic needs to happen. ## If there's a difference, I need the entire hash, %{$element1}, ## saved to the element of a new array with the "CHANGED" key in place } } }


I have prepared myself for enlightenment. (Nothing like a game to "clear the mind." :)

Thanks,
eclecticIO

"Given the pace of technology, I propose we leave math to the machines and go play outside."
Calvin - Homicidal Psycho Jungle Cat

Replies are listed 'Best First'.
(tye)Re: Changing the keys of hashes in arrays
by tye (Sage) on Oct 06, 2000 at 07:50 UTC

    First, you have nested your loops so you are comparing each element of the first array against all of the elements of the second array. Unless all of your hashes are identical (rather than just each pair), most of them will be reported as "changed".

    Second, = is an assignment operator. Perhaps that was just a typo and you meant == which does a numeric comparison. But you should really use eq which is much more general (compares strings).

    Here is some code. I'm not sure I correctly deciphered what you want to do when you find a difference.

    #!/usr/bin/perl -w use strict; use Data::Dumper; my @array1= ( {a=>1,b=>2,c=>3,d=>4}, {w=>0,x=>1,y=>2,z=>3} ); my @array1= ( {a=>1,b=>2,c=>3,d=>4}, {w=>0,x=>4,y=>2,z=>3} ); my @diff; foreach my $i ( 0..$#array1 ) { foreach my $key ( keys %{$array1[$i]} ) { if( $array1[$i]->{$key} ne $array2[$i]->{$key} ) { $diff[$i]= { %{$array1[$i]} }; $diff[$i]->{CHANGED}= delete $diff[$i]->{$key}; last; } } } print Dumper( \@diff );

    The $diff[$i]= { %{$array1[$i]} }; bit copies the entire anonymous hash into a new anonymous hash and stores a reference to it into @diff.

    The $diff[$i]->{CHANGED}= delete $diff[$i]->{$key}; bit deletes the changed key and the delete operator returns the associated value so that you can associate with the new key, "CHANGED".

    This code prints out:

    $VAR1 = [ undef, { 'w' => 0, 'CHANGED' => 1, 'y' => 2, 'z' => 3 } ];

            - tye (but my friends call me "Tye")
RE: Changing the keys of hashes in arrays
by acid06 (Friar) on Oct 06, 2000 at 05:31 UTC
    Hmmm... don't know if this is the best solution (nor if it's really what you meant to do), but this might be what you need:
    use strict; my (@newarray,@array1,@array2); #Fill @array1 and @array2 with hashrefs here... my $count = 0; foreach my $element1 (@array1) { foreach my $element2 (@array2) { foreach my $key (keys %{$element1}) { next if (%{$element1}->{$key} == %{$element2}->{$key}); %{$newarray[$count]} = %{$element1}; my $val = $newarray[$count]->{$key}; delete $newarray[$count]->{$key}; %{$newarray[$count]}->{'CHANGED'} = $val; } } }
RE: Changing the keys of hashes in arrays
by extremely (Priest) on Oct 06, 2000 at 07:23 UTC

    Eeek! -w should yelp about: next if (%{$element1}->{$key} = %{$element2}->{$key});

    Shouldn't that be a '==' for numeric comparison in that if?

    No time for the rest, sorry but I had to point that out.

    --
    $you = new YOU;
    honk() if $you->love(perl)

Re: Changing the keys of hashes in arrays
by eclecticIO (Beadle) on Oct 06, 2000 at 07:50 UTC
    Thanks acid06. That wasn't exactly what I wanted to do, but I made my question vague (the actual script is more complicated than my example). However, your post broke my block and pointed me in the right direction. I've finished that part of the script using the inspiration from your suggestion. Thanks!

    Thanks for the pointer extremely. I'm using -w and do have "eq" in my actualy script but just transposed the wrong thing.

    Thanks again,
    eclecticIO
    "Given the pace of technology, I propose we leave math to the machines and go play outside."
    Calvin - Homicidal Psycho Jungle Cat