Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl6 User-defined comparison function in set opertions

Perl6 documentation indicated that when comparing two items in a set, === is used. This is quote from perl6 documentation:

Objects/values of any type are allowed as set elements. Within a Set, every element is guaranteed to be unique (in the sense that no two elements would compare positively with the === operator)

I am wondering if it is possible to use a user-defined function instead of ===? E.g., How can I use ~~ instead of === in determining whether 2 elements in a set are "equal".

The problem I am trying to solve is this: set A has some first names and some last names in any order but all lower case and no punctuation, and set B has a number of first names and last names mixed in any order, and there may be punctuation attached to the names and may be upper or lower cases. I want to know if a person in set A (represented as a subset of A with one specific first and last name) appears in set B. In this case, I cannot use === because of the letter cases and punctuation in set B.

If I can use ~~ instead of ===, the problem will be much simpler because I only need to determine if a subset of A is also a subset of B using ~~. This is similar to a "permutation match" problem I mentioned before.

Thank you very much !

like image 914
lisprogtor Avatar asked Dec 06 '17 05:12

lisprogtor


1 Answers

There are a couple ways, and I'll start with the easy/slow way. I'll use the == operator, but you can use any operation. If you want to iterate over the list/set, you can use first with whatever match logic you like, then check for .defined to confirm that you got a match. (If you want to be really careful or if your list contains undefined items, you should use the :p adverb so your output is a key/value pair, and that will be defined if and only if some matching element was found.)

For an example of sloppy matching using this technique, I'll search for a number in a list and set of IntStr:

say 4 ∈ ("3", "4"); # False, because the list doesn't contain the integer 4
say ("3", "4").first(* == 4, :p).defined; # True
say set("3", "4").keys.first(* == 4, :p).defined; # True

You would have to benchmark to know whether this is as fast as checking set membership in a more conventional way. For a large set, the conventional ways should be faster, since hash lookup can be used. In some programming languages, iteration is faster than hashing until the list gets really big.

If you don't need to get the matching element, you can use junctions, which will do multiple checks in parallel:

say so ("3", "4").any() == 4; # True

And you can use junctions to do subset testing as well, but since this is an O(m*n) operation (despite being auto-threaded), don't expect high performance when comparing two very large sets.

say so (2, 3).all() == ('1', '2', '3').any(); # True
say so (2, 3, 4).all() == ('1', '2', '3').any(); # False

I used lists instead of sets above, since if you're not using the standard operators/methods, sets offer no speed or API advantage.

like image 62
piojo Avatar answered Nov 03 '22 00:11

piojo