2009-12-16 12 views
64

Esiste una funzione MATLAB incorporata per scoprire se una matrice contiene un determinato valore? (ala del PHP in_array())La funzione per "la matrice contiene il valore X?"

+0

Per dati in virgola mobile in cui può essere desiderata una tolleranza, si noti che la versione R2015a ha aggiunto nuove funzionalità per gestire questo con una singola funzione incorporata.Le soluzioni accettate per i dati con valori interi sono grandi, ma per i float, passa a [questa risposta] (http://stackoverflow.com/a/28907857/2778484). Ci scusiamo per l'auto-promozione, ma è una grande aggiunta a MATLAB dopo anni di domande. – chappjc

risposta

94

Molti modi per farlo. ismember è il primo che viene in mente, dal momento che si tratta di un'azione di appartenenza imposta che si desidera prendere. Così

X = primes(20); 
ismember([15 17],X) 
ans = 
     0 1 

Dal momento che 15 non è primo, ma 17 è, ismember ha svolto bene il suo lavoro qui.

Naturalmente, trovare (o qualsiasi) funzionerà anche. Ma questi non sono vettorizzati nel senso che è stato. Possiamo testare per vedere se 15 è nel set rappresentato da X, ma per testare entrambi i numeri prenderà un ciclo, o test successivi.

~isempty(find(X == 15)) 
~isempty(find(X == 17)) 

o,

any(X == 15) 
any(X == 17) 

Infine, rilevo che i test per i valori esatti sono pericolose se i numeri possono essere veri galleggianti. I test contro i valori interi come ho mostrato sono facili. Ma i test contro i numeri in virgola mobile dovrebbero solitamente utilizzare una tolleranza.

tol = 10*eps; 
any(abs(X - 3.1415926535897932384) <= tol) 
+2

Il più veloce dei tre sembra essere "qualsiasi". Ma potresti volerlo misurare tu stesso (usando 'tic' e' toc'). – Lewistrick

+0

Per i valori in virgola mobile, se si utilizza almeno R2015a, è sufficiente usare ['ismembertol'] (http://stackoverflow.com/a/28907857/2778484). – chappjc

10

si può fare:

A = randi(10, [3 4]);  %# a random matrix 
any(A(:)==5)    %# does A contain 5? 

per ottenere il risultato in un vettorializzare modo, l'uso:

any(bsxfun(@eq, A(:), [5 7 11]) 

o come @woodchips suggerisce:

ismember([5 7 11], A) 
+0

perché stai usando [5 7 11] come argomento in ismember – Jordan

+1

@Jordan: la risposta restituita è una matrice logica (vero/falso) della stessa dimensione dell'argomento, che indica se la matrice 'A' contiene ognuna di quelle valori (es. '[true, true, false]' che significa 'A' contiene i valori' 5' e '7' ma non' 11'). – Amro

+0

ora ho capito, grazie – Jordan

3

Se avete bisogno di controllare se gli elementi di un vettore sono in un altro, la soluzione migliore è ismember come detto in altre risposte.

ismember([15 17],primes(20)) 

Tuttavia, quando si tratta di numeri in virgola mobile, o semplicemente desidera avere vicino le partite (+ - 1000 è anche possibile), la soluzione migliore che ho trovato è il abbastanza efficiente File Exchange Submission: ismemberf

Dà un esempio molto pratico:

[tf, loc]=ismember(0.3, 0:0.1:1) % returns false 
[tf, loc]=ismemberf(0.3, 0:0.1:1) % returns true 

Anche se la tolleranza di default dovrebbe di norma essere sufficiente, ti dà maggiore flessibilità

ismemberf(9.99, 0:10:100) % returns false 
ismemberf(9.99, 0:10:100,'tol',0.05) % returns true 
2

Per i dati in virgola mobile, è possibile utilizzare il nuovo ismembertol function, che calcola l'appartenenza allo con una tolleranza specificata. È simile alla funzione ismemberf trovata in File Exchange, tranne per il fatto che ora è incorporata in MATLAB. Esempio:

>> pi_estimate = 3.14159; 
>> abs(pi_estimate - pi) 
ans = 
    5.3590e-08 
>> tol = 1e-7; 
>> ismembertol(pi,pi_estimate,tol) 
ans = 
    1 
Problemi correlati