2010-06-30 10 views
6

C'è un modo semplice per trovare un array di stringhe di celle più piccolo all'interno di uno più grande? Ho due liste, una con elementi unici e una con elementi ripetuti. Voglio trovare intere occorrenze del modello specifico dell'array più piccolo all'interno del più grande. Sono consapevole che strcmp metterà a confronto due array di celle, ma solo se sono di uguale lunghezza. Il mio primo pensiero è stato di passare attraverso i sottoinsiemi dell'array più grande usando un ciclo, ma ci deve essere una soluzione migliore.Strcmp per array di celle di lunghezza disuguale in MATLAB

Ad esempio, nel seguente:

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

index=myfunction(largecellarray,smallcellarray) 

sarebbero tornati

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

risposta

9

Si potrebbe effettivamente utilizzare la funzione ISMEMBER per ottenere un vettore indice per cui le cellule in largecellarray verificano nella matrice minore smallcellarray, quindi utilizzare la funzione STRFIND (che funziona per le due file e matrici numeriche) per trovare l'inizio indici dell'array piccolo all'interno del più ampio:

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

quindi è una questione di costruzione del vettore index da questi indici iniziali. Ecco un modo si potrebbe creare questo vettore:

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

Un altro modo per creare utilizzando la funzione BSXFUN è data dalla Amro. Un altro modo per creare è:

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

Non riuscirà a produrre il risultato corretto se 'largecellarray' è' {'string3'} '? – Jonas

+0

@Jonas: ottengo 'index = 0' per quel caso, usando la versione più recente della mia soluzione sopra. – gnovice

+0

Oh, ora capisco la tua soluzione. Intelligente! +1 – Jonas

0

ho ottenuto il seguente soluzione di lavoro, ma sto ancora chiedendo se c'è un modo migliore per fare questo:

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 so, lo so, nessun controllo degli errori - Sono una persona orribile.)

1

Nel @gnovice rispondere alla prima parte può essere

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

Non conoscevo grp2idx. Bello! Ma questo non fallirebbe se ci fosse un 'string0' in largecellarray? – Jonas

+0

Sfortunatamente, questo funziona solo se le voci N in 'smallcellarray' sono * esattamente * le stesse delle prime N voci in' largecellarray'. – gnovice

+0

Sì, in molti casi non funzionerà, poiché per grp2idx l'ordine è importante. Probabilmente la funzione di ISMember è importante qui. – yuk

5

Ecco la mia versione (sulla base delle risposte di entrambi @yuk e @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

Soluzione elegante! +1 – Jonas

+0

+1: molto bello, anche se 2 cose dicono: 1) Hai bisogno di [Statistics Toolbox] (http://www.mathworks.de/access/helpdesk/help/toolbox/stats/) per usare [GRP2IDX ] (http://www.mathworks.de/access/helpdesk/help/toolbox/stats/grp2idx.html). 2) La funzione [FINDSTR] (http: //www.mathworks.com/access/helpdesk/help/techdoc/ref/findstr.html) sembra essere previsto per l'obsolescenza a favore di [STRFIND] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/strfind .html). – gnovice

+0

@gnovice: Fix findstr/strfind (notare che l'ordine degli argomenti è importante ora), non ho realizzato che si trattava di una funzione deprecata .. grazie – Amro