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é)?