in reply to How best to compare hash values?

Is there a reason you are using hashes and not arrays? I ask because your keys are only numbers, and nearly sequential numbers at that - this would seem to be the classic example of when to use arrays.

But, assuming you want to do this with hashes, you would first iterate over a sorted key list (see the FAQ How do I sort a hash (optionally by value instead of key)?) and then iterate over that list and output your desired result (How do I process an entire hash?). Something like:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash1 = ("1", "20", "2", "20", "4", "19", "5", "20", "6", "18"); my %hash2 = ("1", "19", "2", "20", "4", "16", "5", "19", "6", "20"); my %differences; for my $key ( sort {$a <=> $b} keys %hash1) { $differences{$key} = $hash1{$key} - $hash2{$key}; print "$key ($hash1{$key} - $hash2{$key}) = $differences{$key}\n"; } print "\n", Dumper \%differences; __END__ 1 (20 - 19) = 1 2 (20 - 20) = 0 4 (19 - 16) = 3 5 (20 - 19) = 1 6 (18 - 20) = -2 $VAR1 = { '6' => -2, '4' => 3, '1' => 1, '2' => 0, '5' => 1 };

and using arrays instead:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @array1 = (undef,20,20,19,20,undef,18); my @array2 = (undef,19,20,16,19,undef,20); my @differences; for my $i (0 .. $#array1) { next unless defined $array1[$i]; $differences[$i] = $array1[$i] - $array2[$i]; print "$i ($array1[$i] - $array2[$i]) = $differences[$i]\n"; } print "\n", Dumper \@differences; __END__ 1 (20 - 19) = 1 2 (20 - 20) = 0 4 (19 - 16) = 3 5 (20 - 19) = 1 6 (18 - 20) = -2 $VAR1 = [ undef, 1, 0, 3, 1, undef, -2 ];

Update: Added storage of differences

Replies are listed 'Best First'.
Re^2: How best to compare hash values?
by jimbass (Novice) on May 05, 2010 at 21:55 UTC

    Thanks guys!

    The reason I went with a hash instead of an array is because I need to know the difference and the key at the same time, IE it is key 1 that has a difference of 1, or key 6 that has a difference of -2. Each key is a radio, and I need to know where to send the crew to fix the radio that fell out of alignment.

    I'm not opposed to using arrays, I simply thought since I needed the value relative to the key, a hash was the way to go.

    It is possible that I get a key in one hash that doesn't appear in another. If a new radio is added without me changing the "perfect" hash then the 'unique' key would appear in hash2, and if a radio loses power or connection then the 'unique' key would appear in hash1. Is there a simple escape from that problem, or should I just let it error out?

      But if your keys are just numbers, then the array index can be the number you need. Note that in my example, I used undef as a place holder for array elements that did not have an entry. Unless your indices are not even remotely sequential or you have non-integer indices, an array will be faster, take less memory and will apply a useful constraint on your keys.

      If there is a possibility that your arrays or hashes do not have equivalent keys, it is considered best practice to test prior to processing those values. Modifying the previously posted codes:

      Hashes:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash1 = ("1", "20", "2", "20", "4", "19", "5", "20", "6", "18", "7", "20"); my %hash2 = ("1", "19", "2", "20", "4", "16", "5", "19", "6", "20", "8", "20"); my %differences; for my $key ( sort {$a <=> $b} keys %hash1) { unless (defined $hash2{$key}) { print "$key is in \%hash1 but not \%hash2\n"; next; } $differences{$key} = $hash1{$key} - $hash2{$key}; print "$key ($hash1{$key} - $hash2{$key}) = $differences{$key}\n"; } print "\n", Dumper \%differences; __END__ 1 (20 - 19) = 1 2 (20 - 20) = 0 4 (19 - 16) = 3 5 (20 - 19) = 1 6 (18 - 20) = -2 7 is in %hash1 but not %hash2 $VAR1 = { '6' => -2, '4' => 3, '1' => 1, '2' => 0, '5' => 1 };

      Arrays:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @array1 = (undef,20,20,19,20,undef,18,20); my @array2 = (undef,19,20,16,19,undef,20,undef,20); my @differences; my $top = $#array1 > $#array2 ? $#array1 : $#array2; for my $i (1 .. $top) { if (defined $array1[$i] and not defined $array2[$i]) { print "$i is in \@array1 but not \@array2\n"; } if (not defined $array1[$i] and defined $array2[$i]) { print "$i is in \@array2 but not \@array1\n"; } next unless defined $array1[$i] and defined $array2[$i]; $differences[$i] = $array1[$i] - $array2[$i]; print "$i ($array1[$i] - $array2[$i]) = $differences[$i]\n"; } print "\n", Dumper \@differences; __END__ 1 (20 - 19) = 1 2 (20 - 20) = 0 3 (19 - 16) = 3 4 (20 - 19) = 1 6 (18 - 20) = -2 7 is in @array1 but not @array2 8 is in @array2 but not @array1 $VAR1 = [ undef, 1, 0, 3, 1, undef, -2 ];

      Note that in the array case, I will not miss that the second set has a value that the first one is missing.

        Excellent, thanks!

        I'll redo my scripts to work with the arrays now, thanks for pointing that possibility out to me.

      You can use for example get_unique and get_complement from List::Compare to check what keys are missing.