J'essaie de trouver la position d'index du plus petit vecteur dans un plus grand.
J'ai déjà résolu ce problème en utilisant strfind
et bind2dec
,
mais je ne veux pas utiliser strfind
, je ne veux pas du tout convertir en chaîne ou en déciamls.
Étant donné le vecteur plus long
result=[15,16,17,18,19,20];
Je veux trouver l'index du plus petit vecteur b dans un
b=[1,1,1,0,0,0];
Je m'attendrais à trouver comme résultat
a=[1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1];
Merci
4 Réponses :
Doit-il être efficace en termes de calcul?
Une solution pas très efficace mais courte serait la suivante:
a = round(rand(1e6,1)); b = round(rand(10,1)); tic;where1 = find(arrayfun(@(n) all(a(n+1:n+length(b))==b),0:length(a)-length(b)));toc; tic;where2 = find_sequence(a,b);toc; >> test_find_sequence Elapsed time is 4.419223 seconds. Elapsed time is 0.042969 seconds.
... vous donne 15. Votre résultat
serait le vecteur where:where+length(b)-1
.
edit : je l'ai essayé et je me tiens corrigée. Voici une version avec des boucles:
function where = find_sequence(a,b) na = 0; where = []; while na < length(a)-length(b) c = false; for nb = 1:length(b) if a(na+nb)~=b(nb) na = na + 1; % + nb c = true; break end end if ~c where = [where,na+1]; na = na + 1; end end
Malgré ses boucles et leur mauvaise réputation dans Matlab, c'est beaucoup plus rapide:
a=[1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1];; b=[1,1,1,0,0,0]; where = find(arrayfun(@(n) all(a(n+1:n+length(b))==b),0:length(a)-length(b)));
Oui, l'efficacité est importante. Aussi je demande parce que strfind et bin2dec nécessitent beaucoup de mémoire pour fonctionner
Essayez celui-ci et voyez comment il se comporte pour vous.Il est inefficace pour les vecteurs plus longs b
car il comparera toujours le vecteur entier alors que l'on pourrait s'arrêter dès qu'il y a une discordance. Pour résoudre ce problème, il faudrait utiliser des boucles qui ne sont pas non plus les plus efficaces de Matlab. Mon instinct est que tant que b
est très court par rapport à a
, cela devrait fonctionner.
D'accord, après les tests, j'ai trouvé que l'utilisation des boucles est considérablement plus rapide. Je viens de voir après avoir posté ma mise à jour que barbsan a déjà suggéré une version très similaire avant moi.
Solution avec pour
boucles:
a=[1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1]; b=[1,1,1,0,0,0]; c = []; b_len = length(b) maxind0 = length(a) - b_len + 1 %no need to search higher indexes for i=1:maxind0 found = 0; for j=1:b_len if a(i+j-1) == b(j) found = found + 1; else break; end end if found == b_len % if sequence is found fill c with indexes for j=1:b_len c(j)= i+j-1; end break end end c %display c
et si new_a = a '? (je transpose a). Aussi b est transposable
si c'est toujours un vecteur, vous pouvez remplacer size (v, 2)
par length (v)
Voici une solution utilisant la convolution 1D. Il peut trouver plusieurs correspondances donc start
contient les indices de début des sous-vecteurs:
f = flip(b); idx = conv(a,f,'same')==sum(b) & conv(~a,~f,'same')==sum(~b); start = find(idx)-ceil(length(b)/2)+1; result = start(1):start(1)+length(b)-1;
Une méthode plus soignée utilisant pour
ressemblerait à ceci, il n'y a pas besoin d'une boucle de vérification interne car nous pouvons vectoriser cela avec all
...
idx = [15,16,17,18,19,20]
Output:
a = [1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1]; b = [1,1,1,0,0,0]; idx = NaN( size(b) ); % Output NaNs if not found nb = numel( b ); % Store this for re-use for ii = 1:numel(a)-nb+1 if all( a(ii:ii+nb-1) == b ) % If matched, update the index and exit the loop idx = ii:ii+nb-1; break end end
Remarque, je trouve cela un peu plus facile à lire que certaines des solutions imbriquées, mais ce n'est pas forcément plus rapide, depuis la comparaison est fait sur tous les éléments de b
à chaque fois.
Quelle est votre solution avec
strfind
? Savez-vous que vous pouvez simplement utiliserstrfind (a, b)
sans convertir en chaînes (mais ce n'est pas documenté)?