I have two lists: excluded and values. I would like to efficiently determine whether excluded and values are disjoint. How does one go about doing this (preferably using FreeQ)?
- 693
- 3
- 9
5 Answers
In version 10.0 you have DisjointQ (and conversely IntersectingQ) to test this. 10.2 adds the Contains* family of function with ContainsNone being equivalent to DisjointQ. For earlier versions you could build this yourself:
ClearAll[disjointQ]
disjointQ[a_List, b_List] := Intersection[a, b] === {}
disjointQ[{1, 2, 3}, {6, 4, 5}]
(* True *)
disjointQ[{1, 2, 3}, {1, 4, 5}]
(* False *)
- 271,378
- 34
- 587
- 1,371
- 65,815
- 14
- 188
- 323
I'd expect this might be faster than intersection on larger lists:
With[{j = Join[DeleteDuplicates@#1, DeleteDuplicates@#2]}, DeleteDuplicates@j == j] &[l1, l2]
Addendum - a little testing, does seem to have advantage when both lists large, otherwise a bit of a wash between this and using intersection... perhaps others can test on non-loungbook environments - I get wildly varying results depending on how I produce the random test lists :-|
Addendum 2: Per comments, differences were from packed/unpacked lists, and in my limited tests the above is faster for unpacked... carry on...
- 25,774
- 2
- 58
- 139
-
Could you give an example of the wildly varying results? I presume it's not simply packed vs. unpacked? – Mr.Wizard Jul 06 '15 at 17:04
-
@Mr.Wizard: {l1,l2}=Random[...,{2,x}] vs l1=Random[...,x];l2=Random[...,x], for example - I'd imagine is cache related on the hampsterbox... – ciao Jul 06 '15 at 17:15
-
And you are running 10.1.0? (Referring to Why does list assignment with a packed array result in unpacked values?) – Mr.Wizard Jul 06 '15 at 17:19
-
@Mr.Wizard: Nope, 10.x still on my voodoo list. And herp-a-derp on my part - could have sworn I checked packing when I got differing results and both cases were unpacked, appears I inadvertently tested same set, so that explains it. – ciao Jul 06 '15 at 17:22
While highly inefficient you asked about FreeQ and you could do this:
f0 = FreeQ[#, Alternatives @@ #2] &;
More practically here is a condensed version of rasher/ciao's method:
f1 = DuplicateFreeQ[Join @@ DeleteDuplicates /@ {##}] &
- 271,378
- 34
- 587
- 1,371
For short lists (see comment of Domen) we could use DeleteElements or UniqueElements
1.
DeleteElements (new in 13.1)
a = {1, 2, 3};
b = {6, 4, 5};
DeleteElements[a, b] == a
True
a = {1, 2, 3};
b = {6, 1, 5};
DeleteElements[a, b] == a
False
2.
With UniqueElements (also new in 13.1) we can test more than 2 lists
a = {1, 2, 3};
b = {6, 4, 5};
c = {9, 8, 7};
UniqueElements[{a, b, c}] == {a, b, c}
True
a = {1, 2, 3};
b = {6, 4, 5};
c = {9, 2, 7};
UniqueElements[{a, b, c}] == {a, b, c}
False
- 67,911
- 5
- 60
- 168
-
Note that these two methods are extremely inefficient (significantly slower than
disjointQfrom the accepted answer). – Domen Jan 02 '24 at 17:40 -
1
Following @eldo's good observation about UniqueElements and grabbing his examples, we can use Tally and MatchQ as follows:
disjointQ[l__List] := MatchQ[Tally[Join[l]][[All, 2]], {1 ..}]
disjointQ[{1, 2, 3}, {6, 4, 5}]
(True)
disjointQ[{1, 2, 3}, {1, 4, 5}]
(False)
a1 = {1, 2, 3};
b1 = {6, 4, 5};
c1 = {9, 8, 7};
disjointQ[a1, b1, c1]
(True)
a2 = {1, 2, 3};
b2 = {6, 4, 5};
c2 = {9, 2, 7};
disjointQ[a2, b2, c2]
(False)
- 23,117
- 3
- 21
- 44
-
1Very nice, +1, but couldn't you use
disjointQ[l__List]for both cases? MakingdisjointQ[a_List, b_List]redundant? – eldo Jan 02 '24 at 23:43 -