2010-09-12 1 views
8

Io sono un po 'in perdita come effettuare le seguenti operazioni in modo efficiente in Mathematica:MemberQ 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], {element,a}] 

risultato atteso è:

{False, True, False, True, False} 

mie liste a e b sono grandi, così Mathematica sta facendo ricerche kazillion lineari attraverso b. Voglio che faccia ricerche più veloci con una tabella hash. Ma sembra che non ci sia una tale struttura. Il più vicino che ho trovato è uno SparseArray, ma

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

è False.

Sono sicuro che questo deve essere possibile in Mathematica in una riga di codice o meno, non riesco a vederlo per gli alberi, o qualcosa del genere.

Qualsiasi eroe in soccorso? Nel frattempo, lo farò con C#.

risposta

7

Un'altra idea sarebbe utilizzare le regole e Dispatch. Sembra essere più veloce quando la lunghezza del blist è grande:

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

membQ = [email protected][MemberQ[blist,#]&/@alist;] 

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

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

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

Sul mio computer portatile, le regole (0.06s) < FCT (0.09s) < sparse (0.9s) < membQ (anni '40).

Modifica/Confronto FCT e regole tempi

@Karsten non esitate a rollback alla tua risposta originale

tabelle generate con il primo [...]

alt text

Tabelle generate con RandomInteger [...]

alt text

+0

Grazie per aver fatto il confronto temporale. Penso che ti meriti la risposta accettata anche se non avevi la risposta più veloce. Ma a tale proposito, il .06 vs .09 non convince: vuoi provarlo con un ordine di grandezza maggiore per assicurarsi che regga? – dreeves

+0

Quale è meglio, sembra dipendere anche da alist e blist. Con alist e blist impostati su RandomInteger [** 100000 **, 800000], la soluzione di Dispatch è migliore di 5.2s rispetto alla soluzione funzionale (5.4), mentre su RandomInteger [** 10000 **, 800000] la soluzione funzionale è più veloce (5.3s contro 5.7s). La soluzione sparsa emette messaggi di errore, che non ho esaminato .. –

+0

Ho riassegnato la risposta accettata, perché dreeves lo richiede. Grazie per i tempi di confronto, mi sento un po 'a disagio a sprecare il tempo della gente in questo modo. :) – Gleno

3

Il filter costruito da ricerca lineare può essere semplificata:

MemberQ[b, #]& /@ a 

Comunque, si potrebbe costruire un array sparso da b da:

s = SparseArray[b -> ConstantArray[True, [email protected]], Max[a, b], False]; 

poi per indici i nella matrice sparsa, s[[i]] restituirà True e per quelli esterni, s[[i]] restituirà False. Così la lista può essere costruito con

s[[#]]& /@ a 

Possiamo paragonare i risultati:

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, [email protected]], 
          Max[alist, blist], False]; 
      s[[#]]& /@ alist;] 

Out[168]= {0.017772,Null} 
+0

quanto riguarda la tua prima frase, probabilmente il richiedente ha solo dire MemberQ [b, elemento] invece di MemberQ [elemento, b]. Per non dire che la tua versione non è migliore. – dreeves

+0

@dreeves: In realtà sto parlando della parte 'Table [..., {element, a}]'. Gli argomenti MemberQ sono una cosa secondaria. – kennytm

+1

Ma non c'è niente di sbagliato nella parte Table [..., {element, a}] (tranne forse che non è efficiente/elegante come la versione basata su Map). Per rimuovere ogni ambiguità al riguardo, penso che andrò avanti e correggerò l'errore di battitura nella domanda in modo da poter effettivamente eseguire l'esempio del richiedente. [Fatto; aggiunto anche l'output previsto.] – dreeves

9

La domanda è equivalente al tuo e contiene una risposta in Mathematica:

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

Ecco la risposta (che riterrò libera di rubare poiché è in realtà la mia):

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

L'idea è di creare una tabella hash, f, che possa rispondere in tempo costante se un dato elemento è un membro della lista b. Prima viene assegnato un valore predefinito di False (se non lo abbiamo visto prima non è in b). Quindi viene eseguito un singolo passaggio nell'elenco b, impostando f [i] su True per ogni i in b. Questo è tutto il set up. Ora una singola passata della funzione hash f sulla lista a ci dà la risposta. Il tempo totale è O (n + m) - un passaggio per ciascuna lista.

+0

Grazie mille, funziona come un fascino. Dove impari comunque le sottili sfumature del pattern matching? Come sai che dura circa O (1), ecc. L'unica cosa che non mi piace della matematica, è che, anche se dovrebbe essere matematica, non elenca quasi mai le complessità. – Gleno

+0

@Gleno Penso che il tuo commento sia un seme molto buono per un'altra domanda :) –

+0

@dreeves Molto elegante! +1 –