in reply to Comparing all keys in a hash

UPDATE
Much faster way in the node below .
If your hashes aren't too large on average I wonder if something like this would be efficient.
sub compare_keys { my ($h1,$h2); my ($k1,$k2) = ( join('',sort keys %$h1), join('',sort keys %$h2) ) +; return $k1 eq $k2 ? 1 : 0; }
Of course I know you're not suppose to rely on hash order but would two hashes with the same keys return in the same order? I would think so but don't know (And don't have time to test) but if it did you could skip the sort. But it probably would be a bad idea.

-Lee

"To be civilized is to deny one's nature."
UPDATE
Fixed typo UPDATE
Fixed typo, thanks Helter

Replies are listed 'Best First'.
Re: Re: Comparing all keys in a hash
by BrowserUk (Patriarch) on Mar 20, 2003 at 14:15 UTC

    If your going to go for the concatenated keys route, then it would be better to use a separator rather than null in the joins to prevent {AA=>1, B=>2} comparing equal to {A=>1, AB=>2}.

    chr(28), the default value of $; is probably as good as any other. Usual caveats apply.

    #! perl -slw use strict; sub cmp_hashes {local $"=$;; #" "@{[ sort keys %{$_[0]} ]}" cmp "@{[ sort keys %{$_[1]} ]}" } my %hashA = ( A=>1, B=>2, C=>3, D=>4 ); my %hashB = ( A=>1, B=>2, C=>3, D=>4 ); my %hashC = ( A=>1, C=>3, D=>4 ); my %hashD = ( A=>1, AB=>2, C=>3, D=>4, E=>5 ); my %hashE = ( AA=>1, B=>2, C=>3, D=>4, E=>5 ); print "hashA cmp hashB =>", cmp_hashes \%hashA, \%hashB; print "hashA cmp hashC =>", cmp_hashes \%hashA, \%hashC; print "hashA cmp hashD =>", cmp_hashes \%hashA, \%hashD; print "hashA cmp hashE =>", cmp_hashes \%hashA, \%hashE; print "hashB cmp hashC =>", cmp_hashes \%hashB, \%hashC; print "hashB cmp hashD =>", cmp_hashes \%hashB, \%hashD; print "hashB cmp hashE =>", cmp_hashes \%hashB, \%hashE; print "hashC cmp hashD =>", cmp_hashes \%hashC, \%hashD; print "hashC cmp hashE =>", cmp_hashes \%hashC, \%hashE; print "hashD cmp hashE =>", cmp_hashes \%hashD, \%hashE; __END__ C:\test>244656 hashA cmp hashB =>0 hashA cmp hashC =>-1 hashA cmp hashD =>1 hashA cmp hashE =>-1 hashB cmp hashC =>-1 hashB cmp hashD =>1 hashB cmp hashE =>-1 hashC cmp hashD =>1 hashC cmp hashE =>-1 hashD cmp hashE =>-1

    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
      slaps($self);
      Good catch. I actually did benchmark the two approaches and diotalevi's is around 25% faster on non matches and the string compare is about 14% faster when hashes match.

      -Lee

      "To be civilized is to deny one's nature."
Re: Re: Comparing all keys in a hash
by Helter (Chaplain) on Mar 20, 2003 at 14:48 UTC
    I had a few spare moments, and tried using your code shotgunefx. You have a curly brace at the end of your second line and I assume you mean a paren.

    Here's some test code to prove my point:
    #!/usr/bin/perl use strict; use warnings; my %h1; my %h2; my %h3; for( my $count = 0, my $char = 'a'; $char ne 'aaaa'; $count++, $char++ + ) { # print "Adding $char with value of $count to h1\n"; $h1{ $char } = $count; } foreach my $key ( keys %h1) { $h2{ $key } = $h1{$key}; } foreach my $key (reverse sort keys %h1) { $h3{ $key } = $h1{$key}; } #foreach my $key (sort keys %h1) { print "h1: key: $key value: $h1{ +$key}\n";} #foreach my $key (sort keys %h2) { print "h2: key: $key value: $h2{ +$key}\n";} #foreach my $key (sort keys %h3) { print "h3: key: $key value: $h2{ +$key}\n";} my ($k1,$k2) = ( join('',sort keys %h1), join('',sort keys %h2) ); my ($k3,$k4) = ( join('',keys %h1), join('',keys %h2) ); my ($k5,$k6) = ( join('',sort keys %h1), join('',sort keys %h3) ); my ($k7,$k8) = ( join('',keys %h1), join('',keys %h3) ); print "inserted same order, keys sorted compare: " . ($k1 eq $k2 ? 1 : + 0) . "\n"; print "inserted same order, keys not sorted compare: " . ($k3 eq $k4 ? + 1 : 0) . "\n"; print "inserted reverse order, keys sorted compare: " . ($k5 eq $k6 ? +1 : 0) . "\n"; print "inserted reverse order, keys not sorted compare: " . ($k7 eq $k +8 ? 1 : 0) . "\n"; __DATA__ Prints: inserted same order, keys sorted compare: 1 inserted same order, keys not sorted compare: 0 inserted reverse order, keys sorted compare: 1 inserted reverse order, keys not sorted compare: 0
    So to answer your question about sorting, the sort of the keys is necessary or the compare will not work.
Re: Re: Comparing all keys in a hash
by rinceWind (Monsignor) on Mar 20, 2003 at 14:35 UTC
    Of course I know you're not suppose to rely on hash order but would two hashes with the same keys return in the same order? I would think so but don't know (And don't have time to test) but if it did you could skip the sort. But it probably would be a bad idea.
    In the current Perl 5 implementation of hashes, you cannot rely of ordering of keys. You may get two canonically identical hashes, which should appear the same, but compare differently without a sort. If the elements were inserted in different sequences, you can see this.

    Try comparing { foo => 1, bar => 5 } with { bar => 5 , foo => 1 }.

    See also this thread

      Actually this does work for me. I think there is an compiler option SHARE_KEYS that I specified when building Perl that might have something to do with it.(I don't remember seeing it in previous version though)

      Regardless, as I originally stated, it's a bad idea to rely on this ordering.

      -Lee

      "To be civilized is to deny one's nature."
Re: Re: Comparing all keys in a hash
by diotalevi (Canon) on Mar 20, 2003 at 18:40 UTC

    You cannot rely on two hashes with the same keys being in the same order. While I'd guess that the key hash values are the same and (maybe) the same hash buckets - that says nothing about the internal order within a bucket. Any algorithm that depends on hash order is flawed unless you a) know exactly how hash order is implemented and b) are comfortable being tied to that specific implementation.

      I understand which is why I cautioned against it, though I thought if the SHARE_KEYS option was compiled it might work. Just playing Devil's Advocate.

      -Lee

      "To be civilized is to deny one's nature."