2010-04-14 27 views

risposta

79

Se hai appena desidera rimuovere gli zeri, lasciando i non-zeri dietro in un, allora la soluzione migliore è

a(a==0) = []; 

Questo elimina gli elementi a zero, utilizzando un approccio logico indicizzazione in MATLAB. Quando l'indice di un vettore è un vettore booleano della stessa lunghezza del vettore, MATLAB può usare quel risultato booleano per indicizzarlo con. Quindi questo è equivalente a

a(find(a==0)) = []; 

E, quando si imposta alcuni elementi di un array a [] in MATLAB, la convenzione è quello di eliminarli.

Se si desidera inserire gli zeri in un nuovo risultato b, lasciando un invariato, il modo migliore è probabilmente

b = a(a ~= 0); 

Anche in questo caso, l'indicizzazione logica è qui utilizzato. Si potrebbe avere utilizzato la versione equivalente (in termini di risultato) di

b = a(find(a ~= 0)); 

ma mlint finirà per contrassegnare la linea, come quella in cui l'indice puramente logico era più efficiente, e quindi più appropriato.

Come sempre, fare attenzione ai test ESATTI per zero o per qualsiasi numero, se si accettano elementi di un valore compreso in una tolleranza epsilonica pari a zero. Effettuate questi test

b = a(abs(a) >= tol); 

Ciò mantiene solo quegli elementi di un valore almeno pari alla vostra tolleranza.

+1

o per il primo esempio, 'a = a (a ~ = 0)' è sufficiente, l'assegnazione sul posto funziona correttamente. Buon punto su test su un numero piccolo piuttosto che su 0. – mtrw

+0

@woodchips: Ho appena postato un confronto delle prestazioni di seguito :) – tim

3
b = a(find(a~=0)) 
+2

just 'b = a (find (a))' è sufficiente, l'impostazione predefinita è trovare valori diversi da zero. – wich

+5

o 'b = a (a ~ = 0)' è sufficiente, l'indicizzazione logica è implicita. – mtrw

+1

Buoni commenti, mi sento male ottenere la mia povera risposta upvoted. –

8

Ho appena imbattuto in questo problema e volevo trovare qualcosa circa le prestazioni, ma non ho potuto, così ho scritto uno script di benchmarking per conto mio:

% Config: 
rows = 1e6; 
runs = 50; 

% Start: 
orig = round(rand(rows, 1)); 

t1 = 0; 
for i = 1:runs 
    A = orig; 
    tic 
    A(A == 0) = []; 
    t1 = t1 + toc; 
end 
t1 = t1/runs; 

t2 = 0; 
for i = 1:runs 
    A = orig; 
    tic 
    A = A(A ~= 0); 
    t2 = t2 + toc; 
end 
t2 = t2/runs; 

t1 
t2 
t1/t2 

Quindi, vedete, la soluzione utilizzando A = A(A ~= 0) è il più veloce dei due :)

4

Spesso ho finito per fare cose come questa. Perciò ho provato a scrivere una semplice funzione che "estrae" gli elementi indesiderati in modo semplice. Questo trasforma la logica MATLAB un po 'a testa in giù, ma sembra buono:

b = snip(a,'0') 

è possibile trovare il file di funzione in: http://www.mathworks.co.uk/matlabcentral/fileexchange/41941-snip-m-snip-elements-out-of-vectorsmatrices

Funziona anche con tutti gli altri 'x', nan o qualsiasi altra cosa elementi.

+6

Questo è un potente martello per schivare una minuscola mosca ... – Shai

2

Perché non solo, a=a(~~a) o a(~a)=[]. È equivalente agli altri approcci, ma certamente meno colpi di chiave.

2

dati

a=[0 3 0 0 7 10 3 0 1 0 7 7 1 7 4] 

fare

aa=nonzeros(a)' 

Risultato

aa=[3 7 10 3 1 7 7 1 7 4] 
+0

Perché non migliorare questo post: aggiungi un link a la documentazione e utilizzare l'evidenziazione corretta per il codice – Sjon

+0

Penso che questa sia un'ottima risposta! Sarebbe bello avere un confronto con altre proposte. –

2

Si potrebbe utilizzare sparse (a), che sarebbe tornato

(1,2) 1

(1,4) 3

Ciò consente di mantenere le informazioni su dove si trovavano le voci non zero.

Problemi correlati