Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
Thanks! (Sorry for double posting, lost url of my original node)my @a = (1, 2, 3); my @b = (2, 3, 1); my @c = (1, 2, 4); &identical(@a, @b) returns 1 &identical(@a, @c) returns 0
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Identical Arrays
by davido (Cardinal) on Aug 26, 2012 at 03:57 UTC | |
This eliminates the sort, instead favoring the efficient operation of constructing a set of unique keys, but assumes elements are unique per array. Essentially we're throwing a little memory at the problem to avoid sorting. As a bonus, we don't even have to care what the elements look like; the hashing handles that for us behind the scenes.
This won't do a deep test. It just tests set equality at face value. If your arrays contain complex data structures you'll need to clarify that point. And again, it assumes each array's elements are unique within that array. This first tests if the two arrays have an equal number of elements (if they don't, there's no point continuing). Then a hash is constructed where each key represents a set entry. Both arrays contribute to the keys. If the number of keys is greater or less than the number of elements in either one of the arrays, we know that we don't have full equality (or in terms familiar to set theory, we do have a symmetric difference). Update: If you cannot assume elements are unique per array you're dealing with a "bag" (or multi-set), and this technique won't be reliable. Dealing with a multi-set you would use two hashes, and store a quantity per key. Then you would have to verify both hashes have all the same keys, and in the same quantity. Still not as inefficient as sorting, but does require two passes through the full range of elements. Here's one way to do that:
And another update: The preceding algorithm could be further optimized. There's no need to keep track of two hashes; we only want to make sure that the net tally between the two hashes is 0 per key. We could do that in a single hash like this:
And now that we've implemented that, we may as well admit we're trying to solve something that has been solved before (many times): We're looking for a condition where there is no symmetric difference between two bags (multisets). Set::Bag works fairly well:
My biggest complaint with Set::Bag is that it stringifies the results, so instead of being happy that $bag_a->difference($bag_b) returns nothing, we instead have to check that $bag_a->difference($bag_b) returns a string that looks like an empty set: '()'. ...and the fact that it's essentially an implementation of the two-hash approach, which can be optimized down to a single-hash. Dave | [reply] [d/l] [select] |
|
Re: Identical Arrays
by Athanasius (Archbishop) on Aug 26, 2012 at 03:07 UTC | |
See the FAQ How do I test whether two arrays or hashes are equal?. Update: If the array elements are numeric, this will work:
Output:
Athanasius <°(((>< contra mundum | [reply] [d/l] [select] |
|
Re: Identical Arrays
by Kenosis (Priest) on Aug 26, 2012 at 06:33 UTC | |
Another option is to use Array::Compare, as it can handle alpha, numeric and alphanumeric array data:
Output:
| [reply] [d/l] [select] |
|
Re: Identical Arrays
by CountZero (Bishop) on Aug 26, 2012 at 07:27 UTC | |
A few comments:
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James My blog: Imperial Deltronics | [reply] [d/l] [select] |
by philiprbrenan (Monk) on Aug 26, 2012 at 13:26 UTC | |
Not so easy!
| [reply] [d/l] |
by CountZero (Bishop) on Aug 26, 2012 at 20:28 UTC | |
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James My blog: Imperial Deltronics | [reply] |
|
Re: Identical Arrays
by Marshall (Canon) on Aug 26, 2012 at 04:28 UTC | |
Oh, don't use either a or b for user Perl variables. In this case, it is ok, but $a and $b are special variables reserved for sort() and other uses. Unlike many other languages, $a is distinct from @a... the same name can be used for different variable types. However, "a" and "b" are so special that I cannot recommend that.
Update: | [reply] [d/l] |
by Anonymous Monk on Aug 26, 2012 at 05:07 UTC | |
| [reply] [d/l] [select] |
by Marshall (Canon) on Aug 26, 2012 at 05:30 UTC | |
I've never used smart match in production code because as this example confirms, it is not as "smart" as one might think! I stand corrected about this. I guess you have to very smart to use the "smart match". Obviously, I am not that smart. | [reply] |
by davido (Cardinal) on Aug 26, 2012 at 06:14 UTC | |
|
Re: Identical Arrays
by BillKSmith (Monsignor) on Aug 27, 2012 at 00:54 UTC | |
Your arrays appear to represent sets. Consider using diffference method of the module Set::Array.
Bill
| [reply] |