2010-06-30 23 views
6

Existe-t-il un moyen facile de trouver un tableau de chaînes plus petit dans un plus grand? J'ai deux listes, une avec des éléments uniques, et une avec des éléments répétitifs. Je veux trouver des occurrences entières du motif spécifique du plus petit tableau dans le plus grand. Je suis conscient que strcmp va comparer deux tableaux de cellules, mais seulement s'ils sont égaux en longueur. Ma première pensée a été de parcourir des sous-ensembles du plus grand tableau en utilisant une boucle, mais il doit y avoir une meilleure solution.Strcmp pour les tableaux de cellules de longueur inégale dans MATLAB

Par exemple, dans les domaines suivants:

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

index=myfunction(largecellarray,smallcellarray) 

retournerait

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

Répondre

9

Vous pouvez réellement utiliser la fonction ISMEMBER pour obtenir un vecteur d'indice pour savoir où les cellules largecellarray se produisent dans le tableau plus petit smallcellarray, puis utilisez la fonction STRFIND (qui fonctionne aussi bien pour les chaînes et tableaux numériques) pour trouver le départ indices du tableau plus petit dans le plus grand:

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

Ensuite, il est une question de la construction du vecteur index de ces indices de départ. Voici une façon vous pouvez créer ce vecteur:

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

Une autre façon de créer à l'aide de la fonction BSXFUN est donnée par Amro. Une autre façon de créer est:

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

Est-ce que cela ne produira pas le résultat correct si 'largecellarray' est' {'string3'} '? – Jonas

+0

@Jonas: J'obtiens 'index = 0' pour ce cas, en utilisant la dernière version de ma solution ci-dessus. – gnovice

+0

Oh, maintenant je comprends votre solution. Intelligent! +1 – Jonas

0

je suis arrivé le travail de solution suivante, mais je me demande encore s'il y a une meilleure façon de le faire:

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 

(Je sais, je sais, aucune vérification d'erreur - Je suis une personne horrible.)

1

En @gnovice répondre à la première partie peut être

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

Je ne connaissais pas grp2idx. Agréable! Mais cela n'échouerait-il pas s'il y avait un 'string0' dans le grand magasin? – Jonas

+0

Malheureusement, cela ne fonctionne que si les N entrées dans 'smallcellarray' sont * exactement * les mêmes que les N premières entrées de' largecellarray'. – gnovice

+0

Oui, il échouera dans de nombreux cas, car pour grp2idx l'ordre est important. La fonction ismember est probablement importante ici. – yuk

5

Voilà ma version (sur la base des réponses des deux @yuk et @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

Solution élégante! +1 – Jonas

+0

+1: Très bien, bien que 2 choses à mentionner: 1) Vous avez besoin de la [Statistics Toolbox] (http://www.mathworks.de/access/helpdesk/help/toolbox/stats/) pour utiliser [GRP2IDX ] (http://www.mathworks.de/access/helpdesk/help/toolbox/stats/grp2idx.html). 2) La fonction [FINDSTR] (http: //www.mathworks.com/access/helpdesk/help/techdoc/ref/findstr.html) semble être destiné à l'obsolescence en faveur de [STRFIND] (http://www.mathworks.com/access/helpdesk/help/techdoc/ref/strfind .html). – gnovice

+0

@gnovice: Correction de findstr/strfind (notez que l'ordre des arguments est important maintenant), je ne me suis pas rendu compte que c'était une fonction obsolète .. merci – Amro