This could turn into a golf exercise I suppose.sub compare_hash_keys { my ($h1,$h2) = @_; my @k1 = sort keys %$h1; my @k2 = sort keys %$h2; return @k2 - @k1 if @k1 <=> @k2; for (0..$#k1) { return $k1[$_] cmp $k2[$_] if $k1[$_] cmp $k2[$_]; } 0; }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Comparing all keys in a hash
by gmax (Abbot) on Mar 20, 2003 at 12:03 UTC | |
Actually, the way you are doing it, you are comparing arrays. Therefore you may find useful this node: The best method there was MeowChow's at (MeowChow) Re2: (Efficiently) comparing arrays To take advantage of hashes capabilities, though, I would rather use something like
The first sub returns an array of keys present in one hash and missing in the other one. The second one combines the differences in both hashes. I think you may use this method to implement what is closer to your needs. _ _ _ _ (_|| | |(_|>< _| | [reply] [d/l] |
|
Re: Comparing all keys in a hash
by diotalevi (Canon) on Mar 20, 2003 at 11:50 UTC | |
A nit - don't sort the arrays until you've done your @k1 <=> @k2 test. If that returns true then you wasted two sort() ops. Also, do your cmp operation once and stash the result in a my() variable. Its fast, easy and saves redundant work.
| [reply] [d/l] [select] |
|
Re: Comparing all keys in a hash
by shotgunefx (Parson) on Mar 20, 2003 at 14:58 UTC | |
-Lee "To be civilized is to deny one's nature." | [reply] [d/l] |
|
Re: Comparing all keys in a hash
by shotgunefx (Parson) on Mar 20, 2003 at 13:48 UTC | |
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. 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 | [reply] [d/l] |
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.
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. | [reply] [d/l] |
by shotgunefx (Parson) on Mar 20, 2003 at 14:40 UTC | |
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." | [reply] |
by Helter (Chaplain) on Mar 20, 2003 at 14:48 UTC | |
Here's some test code to prove my point: So to answer your question about sorting, the sort of the keys is necessary or the compare will not work. | [reply] [d/l] |
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 | [reply] [d/l] [select] |
by shotgunefx (Parson) on Mar 20, 2003 at 19:14 UTC | |
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." | [reply] |
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. | [reply] |
by shotgunefx (Parson) on Mar 20, 2003 at 19:10 UTC | |
-Lee "To be civilized is to deny one's nature." | [reply] |
|
Re: Comparing all keys in a hash
by demerphq (Chancellor) on Mar 20, 2003 at 23:28 UTC | |
I have to say that I really wonder about this node and thread. The code is interesting in its own way, and the discussion below has some merit I suppose, but I can't help but question a bunch of things. First off what does this routine do? It "compares" two hashes. Presumably the hashes are of numbers? Its a litte unclear if they are because sort keys %$h1 sorts them lexicographically. I think you want sort {$a <=> $b} keys %$h1. Next is the issue of what you return. You return the difference in the number of elements if they are different, otherwise you return which of the two has a lower element encoded ala <=>. What I wonder is why? Why is a hash that contains a single key, say 100000 smaller than a hash with two keys, say 1,2? Why is a hash with keys (0,1,100,200) smaller than a hash with (0,2,2,2)? If I saw this code in production without considerable explanation as to its use and relevance I would earmark it for a rewrite as being misconceived. Either it should be renamed, or it should be refactored, or it should be redone. It just doesnt make sense... --- demerphq <Elian> And I do take a kind of perverse pleasure in having an OO assembly language... | [reply] [d/l] [select] |
by rinceWind (Monsignor) on Mar 21, 2003 at 10:00 UTC | |
This code is part of an application process monitoring GUI, that uses Tk. The hash keys are process IDs, and this sub is used to decide whether anything has changed (hence whether to backtick a ps and poll the application's control files - which are expensive activities). In practice, the code only needs a zero or non-zero value, so the spaceship operator like return value is overkill. After writing the code, it seemed like an interesting exercise to see if the code could have been written better, hence my meditation on PM. Hope this answers your questions. Your post has prompted me to add some comments to the code. | [reply] |
by demerphq (Chancellor) on Mar 21, 2003 at 14:54 UTC | |
Ok. Now I get it. :-) Personally I would return very different results...
This seems like a much more reasonable return to me, and considering the use you put it to it would seem to be more convenient as well: this would give you a list of processes that have been removed, as well as processes that have started. BTW: You didnt overlook my point about the sort order did you? Anyway, thanks for the explanation. --- demerphq | [reply] [d/l] [select] |
by shotgunefx (Parson) on Mar 21, 2003 at 10:10 UTC | |
-Lee "To be civilized is to deny one's nature." | [reply] |
|
Re: Comparing all keys in a hash
by rir (Vicar) on Mar 21, 2003 at 20:54 UTC | |
an artifact of optimization? Or is this part of your definition of comparing the keys of two hashes? | [reply] [d/l] |