2010-07-12 32 views
8

Tengo dos matrices de cadenas de celdas, y quiero comprobar si contienen las mismas cadenas (no tienen que estar en el mismo orden, ni sabemos si son de las mismas longitudes).MATLAB: comparación de matrices de celdas de la cadena

Por ejemplo:

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

o

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

principio pensé en strcmp pero requeriría más de un bucle contenido de la celda y compara contra el otro. También consideré ismember utilizando algo como:

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

pero entonces no sé de antemano que son de la misma longitud (caso evidente de la desigualdad). Entonces, ¿cómo haría esta comparación de la manera más eficiente sin escribir demasiados casos de if/else?

Respuesta

17

Puede usar la función SETXOR, que devolverá los valores que no están en la intersección de las dos matrices de celdas. Si devuelve una matriz vacía, entonces las dos matrices celulares contienen los mismos valores:

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



EDIT: Algunas medidas de rendimiento ...

Puesto que has sido curioso sobre las medidas de rendimiento, pensé en probar la velocidad de mi solución contra las dos soluciones enumeradas por Amro (que usan ISMEMBER y STRCMP/CELLFUN). Creé primera dos grandes conjuntos de células:

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

siguiente, me encontré con cada solución de 100 veces para obtener un tiempo medio de ejecución. Luego, cambié a y b y lo reintervine. Aquí están los resultados:

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 ;) 

en cuenta que la solución SETXOR tiene tiempo rápido y consistente. La solución ISMEMBER en realidad se ejecutará un poco más rápido si a tiene elementos que no están en b. Esto se debe al short-circuit && que omite la segunda mitad del cálculo (porque ya sabemos que a y b no contienen los mismos valores). Sin embargo, si todos los valores en a también están en b, la solución ISMEMBER es significativamente más lenta.

+1

Para medir el rendimiento, necesitaría otra solución para comparar, como la sugerencia que hizo mediante un bucle y [STRCMP] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/strcmp. html). Imagino que el rendimiento sería perfecto, pero si descubres que el uso de [SETXOR] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/setxor.html) realmente termina siendo un cuello de botella en su procesamiento, puede intentar ver su código fuente ('type setxor' o' edit setxor') y reescribirlo mediante el recorte de alguna comprobación de errores, etc. – gnovice

+1

gracias, creo que veo lo que @Mikhail estaba tratando de hacer. ¿Qué hay del rendimiento? parece que XOR de dos conjuntos es una operación costosa cuando todo lo que necesitaba es un tipo de respuesta verdadero/falso – Dave

+0

Vaya, edité mi comentario y arruiné el pedido ... lo siento – Dave

2

Echa un vistazo a la función intersect

Lo MATLAB Ayuda dice: vectores

[c, ia, ib] = intersect(a, b) también la rentabilidad del índice de columna ia y ib tal que c = a(ia) y b(ib) (o c = a(ia,:) y b(ib,:)).

+0

No estoy seguro de cómo obtener la solución del resultado de 'interseca' – Dave

+0

Depende de lo que exactamente tienes que hacer. Si necesita un booleano escalar para que ambos vectores contengan las mismas cadenas, entonces la solución por gnovice es la respuesta correcta para usted. – Mikhail

5

Puede seguir utilizando la función IsMember igual que lo hizo con una pequeña modificación:

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

Además, se puede escribir la versión de bucle con STRCMP como una línea:

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

EDITAR: Estoy agregando una tercera solución adaptada de otra SO question:

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

En el mismo espíritu, Im realizó la comparación del tiempo (usando la función 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 

y los resultados en el mismo orden de funciones (menos es mejor):

ans = 
    0.032527 
ans = 
    0.055853 
ans = 
     8.6431 
ans = 
    0.022362 
Cuestiones relacionadas