开发者

MemberQ in Mathematica

I am a bit at a loss how to do the following efficiently in Mathematica:

a = { 1, 2, 3, 4, 5 };  (* list of integers *)
b = { 2, 4, 6, 8 };     (* another list of integers *)
filter = Table[MemberQ[b, element], {el开发者_运维百科ement,a}]

Expected output is:

{False, True, False, True, False}

My lists a and b are big, so Mathematica is doing a kazillion linear searches through b. I want it to do faster lookups with a hashtable. But there seems to be no such structure. The closest I could find is a SparseArray, but

sa = SparseArray[{1 -> True, 2 -> True}];
MemberQ[sa, 1]

is False.

I'm sure this must be possible in Mathematica in one line of code or less, I just can't see it for the trees, or something.

Any hero to the rescue? Meanwhile, I'm going to do this with C#.


The following question is equivalent to yours and contains an answer in Mathematica:

https://stackoverflow.com/questions/1954636/given-list-subset-of-list-return-bitmask

Here's that answer (which I'll feel free to steal since it's actually mine):

bitmask[a_, b_] := Module[{f},
  f[_] = False;
  (f[#] = True)& /@ b;
  f /@ a]

The idea is to make a hash table, f, that can answer in constant time whether a given element is a member of list b. First f is given a default value of False (if we haven't seen it before it's not in b). Then a single pass through the list b is made, setting f[i] to True for each i in b. That's all the set up. Now a single pass of the hash function f over the list a gives us the answer. Total time is O(n+m) -- one pass through each list.


Another idea would be to use rules and Dispatch. It seems to be faster when the length of the blist is large:

alist = Prime /@ Range[20000];
blist = alist + 2;

membQ = First@Timing[MemberQ[blist,#]&/@alist;]

sparse = First@Timing[
    s = SparseArray[blist -> ConstantArray[True, Length@blist], Max[alist, blist], False];
    s[[#]] & /@ alist;
]

rules = First@Timing[
    bRules = Dispatch[Append[Rule[#, True] & /@ blist, _ -> False]];
    (# /. bRules) & /@ alist;
]

fct = First@Timing[
    f[_] = False;
    (f[#] = True) & /@ blist;
    f /@ alist;
]

On my laptop, rules (0.06s) < fct (0.09s) < sparse (0.9s) < membQ (40s).

Edit / Comparing fct and rules timings

@Karsten please feel free to rollback to your original answer

Tables generated with Prime[...]

MemberQ in Mathematica

Tables generated with RandomInteger[...]

MemberQ in Mathematica


The filter constructed by linear search can be simplified to:

MemberQ[b, #]& /@ a

Anyway, you could construct a sparse array from b by:

s = SparseArray[b -> ConstantArray[True, Length@b], Max[a, b], False];

then for indices i in the sparse array, s[[i]] will return True, and for those outside, s[[i]] will return False. So the list can be constructed with

s[[#]]& /@ a

We can compare the results:

In[130]:= alist = Prime /@ Range[2000];
          blist = alist + 2;

In[165]:= Timing[MemberQ[blist, #]& /@ alist;]

Out[165]= {0.91024,Null}

In[168]:= Timing[
           s = SparseArray[blist -> ConstantArray[True, Length@blist],
                           Max[alist, blist], False];
           s[[#]]& /@ alist;]

Out[168]= {0.017772,Null}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜