2010-06-30 12 views
6

¿Hay alguna manera fácil de encontrar una matriz de celdas más pequeña dentro de una más grande? Tengo dos listas, una con elementos únicos y otra con elementos repetitivos. Quiero encontrar ocurrencias enteras del patrón específico de la matriz más pequeña dentro de la más grande. Soy consciente de que strcmp comparará dos matrices de celdas, pero solo si son iguales en longitud. Mi primer pensamiento fue atravesar subconjuntos de la matriz más grande usando un bucle, pero tiene que haber una mejor solución.Strcmp para matrices de celdas de longitud desigual en MATLAB

Por ejemplo, en el siguiente:

smallcellarray={'string1',... 
       'string2',... 
       'string3'}; 
largecellarray={'string1',... 
       'string2',... 
       'string3',... 
       'string1',... 
       'string2',... 
       'string1',... 
       'string2',... 
       'string3'}; 

index=myfunction(largecellarray,smallcellarray) 

volvería

index=[1 1 1 0 0 1 1 1] 

Respuesta

9

En realidad se podría utilizar la función ISMEMBER para obtener un vector de índice para dónde se producen las células en largecellarray en la matriz más pequeña smallcellarray, a continuación, utilizar la función de STRFIND (que funciona para ambas cadenas y matrices numéricas) para encontrar la partida índices de la matriz más pequeña dentro de la grande:

>> nSmall = numel(smallcellarray); 
>> [~, matchIndex] = ismember(largecellarray,... %# Find the index of the 
           smallcellarray); %# smallcellarray entry 
                %# that each entry of 
                %# largecellarray matches 
>> startIndices = strfind(matchIndex,1:nSmall) %# Starting indices where the 
               %# vector [1 2 3] occurs in 
startIndices =         %# matchIndex 

    1  6 

entonces es una cuestión de construir el vector index de estos índices de inicio. He aquí una forma de poder crear este vector:

>> nLarge = numel(largecellarray); 
>> endIndices = startIndices+nSmall; %# Get the indices immediately after 
             %# where the vector [1 2 3] ends 
>> index = zeros(1,nLarge);   %# Initialize index to zero 
>> index(startIndices) = 1;   %# Mark the start index with a 1 
>> index(endIndices) = -1;   %# Mark one index after the end with a -1 
>> index = cumsum(index(1:nLarge)) %# Take the cumulative sum, removing any 
             %# extra entry in index that may occur 
index = 

    1  1  1  0  0  1  1  1 

Otra forma de crear utilizando la función BSXFUN está dada por Amro. Sin embargo, otra manera de crear es:

index = cumsum([startIndices; ones(nSmall-1,numel(startIndices))]); 
index = ismember(1:numel(largecellarray),index); 
+0

¿No se producirá el resultado correcto si 'largecellarray' es' {'string3'} '? – Jonas

+0

@Jonas: obtengo 'index = 0' para ese caso, usando la versión más nueva de mi solución anterior. – gnovice

+0

Oh, ahora entiendo tu solución. ¡Inteligente! +1 – Jonas

0

me dio la siguiente solución de trabajo, pero todavía estoy preguntando si hay una mejor manera de hacer esto:

function [output]=cellstrcmpi(largecell,smallcell) 
output=zeros(size(largecell)); 
idx=1; 
while idx<=length(largecell)-length(smallcell)+1 
    if sum(strcmpi(largecell(idx:idx+length(smallcell)-1),smallcell))==length(smallcell) 
     output(idx:idx+length(smallcell)-1)=1; 
     idx=idx+length(smallcell);  
    else 
     idx=idx+1; 
    end 
end 

(Lo sé, lo sé, sin errores al verificar - Soy una persona horrible.)

1

En @gnovice responder a la primera parte puede ser

l = grp2idx(largecellarray)'; 
s = grp2idx(smallcellarray)'; 
startIndices = strfind(l,s); 
+0

No sabía grp2idx. ¡Bonito! Pero, ¿esto no fallaría si hubiera un 'string0' en largecellarray? – Jonas

+0

Desafortunadamente, esto solo funciona si las N entradas en 'smallcellarray' son * exactamente * las mismas que las primeras N entradas en' largecellarray'. – gnovice

+0

Sí, en realidad fallará en muchos casos, ya que para grp2idx el orden es importante. Probablemente la función ismember sea importante aquí. – yuk

5

aquí está mi versión (basado en las respuestas de ambos @yuk y @gnovice):

g = grp2idx([S L])'; 
idx = strfind(g(numel(S)+1:end),g(1:numel(S))); 
idx = bsxfun(@plus,idx',0:numel(S)-1); 

index = zeros(size(L)); 
index(idx(:)) = 1; 
+0

¡Solución elegante! +1 – Jonas

+0

+1: Muy bien, aunque hay dos cosas que mencionan: 1) Necesita [Statistics Toolbox] (http://www.mathworks.de/access/helpdesk/help/toolbox/stats/) para usar [GRP2IDX ] (http://www.mathworks.de/access/helpdesk/help/toolbox/stats/grp2idx.html). 2) La función [FINDSTR] (http: //www.mathworks.com/access/helpdesk/help/techdoc/ref/findstr.html) parece estar programado para ser obsoleto a favor de [STRFIND] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/strfind .html). – gnovice

+0

@gnovice: Fixed findstr/strfind (tenga en cuenta que el orden de los argumentos es importante ahora), no me di cuenta de que era una función en desuso ... gracias – Amro

Cuestiones relacionadas