If you have to perform many checks of this kind, it might justify the overhead to create a lookup table in form of an Association
.
The first thing here is a listable variant of Sort
that also employs parallelization.
sort = Compile[{{list, _Integer, 1}},
Sort[list],
RuntimeAttributes -> {Listable},
Parallelization -> True
];
This will be the replacement for MemberQ
. Note that we
memberQ[S_Association, R_?MatrixQ] := Unitize[Lookup[S, sort@R, 0]];
memberQ[S_Association, R_?VectorQ] := Unitize[Lookup[S, sort[{R}], 0]][[1]];
Some not so big test data...
n = 2000;
m = 30;
d = 3;
T = DeleteDuplicates[sort@RandomInteger[{1, m}, {n, d}]];
R = RandomInteger[{1, m}, {n, d}];
Now, we create the lookup table S
for T
:
S = AssociationThread[sort@T, Range[Length[T]]]; // AbsoluteTiming // First
0.002173
And this is how our new memberQ
compares to MemberQ
in conjunction with Sort
:
a = Boole[MemberQ[T, Sort[#]] & /@ R]; // AbsoluteTiming // First
b = memberQ[S, R]; // AbsoluteTiming // First
a == b
0.496145
0.001229
True
This will also work well for longer lists. For lists of length d=2
, it is more efficient to use a SparseArray
as lookup table. For short lists of given length d
, this can be further improved by writing specialized and compiled sorting routines.
Sort
subsets first.... $\endgroup$MemberQ
check often? $\endgroup$