3
$\begingroup$

Consider the following two lists:

listtest = {11, 13, 22, 221, 1, 3} // Sort // N;
pdglisttest = RandomInteger[{-222, 222}, 10^6] // N;

For the given element of pdglisttest, I want to return 1 if it belongs to listtest and 0 otherwise. In the real case, listtest and pdgtest are not fixed, and this operation is just a sub-action required when calculating some quantity.

I make two codes - one using MemberQ and another one without it, by using explicit If:

comp = Compile[{{list, _Real, 1}, {pdglist, _Real}}, 
  If[MemberQ[list, Abs[pdglist]], 1, 0], CompilationTarget -> "C", 
  RuntimeAttributes -> {Listable}, RuntimeOptions -> "Speed"]
comp1 = Compile[{{pdglist, _Real}},
  Module[{pdg},
   pdg = Abs[pdglist];
   If[pdg == 1. || pdg == 3. || pdg == 11. || pdg == 13. || 
     pdg == 22. || pdg == 221., 1, 0]
   ], CompilationTarget -> "C", RuntimeAttributes -> {Listable}, 
  RuntimeOptions -> "Speed"]

It turns out that the one with MemberQ is triple as slow:

t=comp[listtest, pdglisttest]; // AbsoluteTiming
t1=comp1[pdglisttest]; // AbsoluteTiming
t==t1

{0.0855261,Null}

{0.0257923,Null}

True

However, MemberQ is very convenient and probably unavoidable if pdglist is not fixed. Is it possible to speed it up, or the slowdown cannot be handled?

Edit

Adding the option Parallelization->True to both codes reduces the timing difference down to a factor of 1.5-2, but it is still present.

$\endgroup$
2
  • 1
    $\begingroup$ Have you tried explicitly adding a levelspec? It might help because it does not try to 'dig deeper'… $\endgroup$
    – SHuisman
    Commented Dec 19, 2023 at 10:58
  • 1
    $\begingroup$ Again: I recommend to sort listtest and run a binary search. Should be the same algorithm as in MemberQ (but compilable). $\endgroup$ Commented Dec 19, 2023 at 16:26

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.