2010-07-12 50 views
8

Ho due array di celle di stringhe e voglio verificare se contengono le stesse stringhe (non devono essere nello stesso ordine, né sappiamo se sono di le stesse lunghezze).MATLAB: confronto di array di celle di stringa

Ad esempio:

a = {'2' '4' '1' '3'}; 
b = {'1' '2' '4' '3'}; 

o

a = {'2' '4' '1' '3' '5'}; 
b = {'1' '2' '4' '3'}; 

primo momento ho pensato di strcmp ma richiederebbe loop oltre un contenuto delle celle e confrontare con l'altro. Ho anche considerato ismember usando qualcosa come:

ismember(a,b) & ismember(b,a) 

ma poi non so in anticipo che sono della stessa lunghezza (caso evidente di disuguale). Quindi, come eseguiresti questo confronto nel modo più efficiente senza scrivere troppi casi di se/else.

risposta

17

È possibile utilizzare la funzione SETXOR, che restituirà i valori che non si trovano nell'intersezione dei due array di celle. Se restituisce un array vuoto, poi i due array di celle contengono gli stessi valori:

arraysAreEqual = isempty(setxor(a,b)); 



EDIT: Alcune misure di performance ...

Dal momento che si erano curiosi sulle misure di prestazione, ho pensato di testare la velocità della mia soluzione rispetto alle due soluzioni elencate da Amro (che utilizzano ISMEMBER e STRCMP/CELLFUN). Ho creato due grandi array di celle:

a = cellstr(num2str((1:10000).')); %'# A cell array with 10,000 strings 
b = cellstr(num2str((1:10001).')); %'# A cell array with 10,001 strings 

Avanti, ho corso ogni soluzione 100 volte per ottenere un tempo di esecuzione media. Quindi, ho scambiato a e b e l'ho reran. Ecco i risultati:

Method  |  Time  | a and b swapped 
---------------+---------------+------------------ 
Using SETXOR | 0.0549 sec | 0.0578 sec 
Using ISMEMBER | 0.0856 sec | 0.0426 sec 
Using STRCMP |  too long to bother ;) 

nota che la soluzione SETXOR ha tempi costantemente veloci. La soluzione ISMEMBER verrà effettivamente eseguita leggermente più veloce se a ha elementi che non sono in b. Ciò è dovuto allo short-circuit && che salta la seconda metà del calcolo (perché sappiamo già a e non contengono gli stessi valori). Tuttavia, se tutti i valori in si trovano anche in b, la soluzione ISMEMBER è notevolmente più lenta.

+1

Per valutare le prestazioni, è necessaria un'altra soluzione da confrontare, come il suggerimento che hai fatto usando un ciclo e [STRCMP] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/strcmp. html). Immagino che le prestazioni siano perfette, ma se scopri che l'uso di [SETXOR] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/setxor.html) finisce davvero per essere un collo di bottiglia nel processo, puoi provare a guardare il suo codice sorgente ('tipo setxor' o' edit setxor') e riscriverlo tagliando alcuni errori di controllo, ecc. – gnovice

+1

grazie, penso di vedere cosa stava cercando @Mikhail fare. Che dire delle prestazioni? sembra che XOR di due set sia un'operazione costosa quando tutto ciò di cui avevo bisogno è un tipo di risposta vero/falso – Dave

+0

oops, ho modificato il mio commento e ho incasinato l'ordine .. scusa – Dave

2

Date un'occhiata alla funzione intersect

Cosa MATLAB Aiuto dice: vettori

[c, ia, ib] = intersect(a, b) anche rendimenti dell'indice colonna ia e ib tale che c = a(ia) e b(ib) (o c = a(ia,:) e b(ib,:)).

+0

Non sono sicuro di come ottenere la soluzione dal risultato di 'intersect' – Dave

+0

Dipende da cosa devi fare esattamente. Se hai bisogno di un booleano scalare che entrambi i vettori contengano le stesse stringhe, allora la soluzione di gnovice è la risposta giusta per te. – Mikhail

5

È comunque possibile utilizzare la funzione IsMember come avete fatto con una piccola modifica:

arraysAreEqual = all(ismember(a,b)) && all(ismember(b,a)) 

Inoltre, è possibile scrivere la versione ciclo con STRCMP come una riga:

arraysAreEqual = all(cellfun(@(s)any(strcmp(s,b)), a)) 

EDIT: Sto aggiungendo una terza soluzione adattata da un'altra SO question:

g = grp2idx([a;b]); 
v = all(unique(g(1:numel(a))) == unique(g(numel(a)+1:end))); 

Nello stesso spirito, Im eseguito il confronto temporale (utilizzando la funzione TIMEIT):

function perfTests() 
    a = cellstr(num2str((1:10000)'));   %#' fix SO highlighting 
    b = a(randperm(length(a))); 

    timeit(@() func1(a,b)) 
    timeit(@() func2(a,b)) 
    timeit(@() func3(a,b)) 
    timeit(@() func4(a,b)) 
end 

function v = func1(a,b) 
    v = isempty(setxor(a,b));      %# @gnovice answer 
end 

function v = func2(a,b) 
    v = all(ismember(a,b)) && all(ismember(b,a)); 
end 

function v = func3(a,b) 
    v = all(cellfun(@(s)any(strcmp(s,b)), a)); 
end 

function v = func4(a,b) 
    g = grp2idx([a;b]); 
    v = all(unique(g(1:numel(a))) == unique(g(numel(a)+1:end))); 
end 

ed i risultati nello stesso ordine delle funzioni (più basso è migliore):

ans = 
    0.032527 
ans = 
    0.055853 
ans = 
     8.6431 
ans = 
    0.022362 
Problemi correlati