convert consecutive ones into alternating one/zero's
Mostrar comentarios más antiguos
I need to convert a vector consisting of ones and zero's such that consecutive blocks of 1's will be replaced by alternating ones and zeros. Example:
[0 1 0 1 0 0 1 1 0 1 1 1 1 0 1] needs to be converted to:
[0 1 0 1 0 0 1 0 0 1 0 1 0 0 1]
Of course that can be done in a loop, but I'm looking for a vectorized way of accomplishing this. Any ideas?
5 comentarios
Jan
el 27 de Nov. de 2012
Please explain the wanted procedure with enough details. Currently it is unlikely that we can guess the conversion rules exactly.
William Reinders
el 27 de Nov. de 2012
Editada: Image Analyst
el 27 de Nov. de 2012
Arthur
el 27 de Nov. de 2012
It is maybe more elegant to vectorize it, but do you really need it? The loop you suggest yourself is very easy to understand, and fast. For 1e6 flags it took my pc less then 40 ms. So I'd just go for the loop....
Jan
el 27 de Nov. de 2012
+1: Thanks for this interesting problem. Sometime I love the bit nudging.
Respuesta aceptada
Más respuestas (4)
Sean de Wolski
el 27 de Nov. de 2012
One of many ways:
double(regexprep(char([0 1 0 1 0 0 1 1 0 1 1 1 1 0 1]),char([1 1]),char([1 0])))
hint This is certainly not the best way!
Compare the timings with this cleaned loop method:
for k = 2:length(flags)
if flags(k-1) && flags(k)
flags(k) = 0;
end
end
Note, that the JIT accelerator can profit from using one command per line only.
[EDITED] I assume the program is noticably faster when flag is a logical array.
1 comentario
Matt Fig
el 27 de Nov. de 2012
+1 see the WHILE loop version too.
Image Analyst
el 27 de Nov. de 2012
Do you have the Image Processing Toolbox, because this is fairly easy if you have it, though you'd still need at least one for loop over each connected component but not two for loops like your brute force method would:
m = [0 1 0 1 0 0 1 1 0 1 1 1 1 0 1]
blobs = regionprops(logical(m), 'PixelIdxList');
for blobNumber = 1 : length(blobs)
thisBlobsIndexes = blobs(blobNumber).PixelIdxList
m(thisBlobsIndexes(2:2:end)) = 0;
end
% Print out
m
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
mxLogical *In, *Out;
mwSize i, n;
if (!mxIsLogical(prhs[0])) {
mexErrMsgTxt("Input must be a logical vector.");
}
In = (mxLogical *) mxGetData(prhs[0]);
n = mxGetNumberOfElements(prhs[0]);
plhs[0] = mxCreateLogicalMatrix(1, n);
Out = (mxLogical *) mxGetData(plhs[0]);
/* The FOR loop approach: */
/* Out[0] = In[0];
* for (i = 1; i < n; i++) {
* if (In[i]) {
* if (!Out[i - 1]) {
* Out[i] = true;
* }
* }
*}
*/
/* Matt Fig's faster WHILE: */
i = 2;
while (i < n) {
if (In[i] && !In[i - 1]) {
Out[i] = true;
i += 2;
} else {
i++;
}
}
return;
}
Timings:
- Test data: A = rand(1, 1e8) > 0.05;
- Matlab 2009a/64, Win7, Core2Duo
- MEXed FOR loop: 0.49 sec
- MEXed WHILE loop: 0.28 sec
- Matlab WHILE: 1.26 sec
- Matlab FOR: 1.90 sec
- Original Matlab FOR: 2.33 sec (if A(i)==1 && A(i+1)==1)
2 comentarios
William Reinders
el 28 de Nov. de 2012
Jan
el 28 de Nov. de 2012
- The comparison with 1 in A(i)==1 && A(i+1)==1 consumes time. Using A(i) && A(i+1) is faster already.
- When the while loop sets a value to 0, it avoids testing the following element, because it is not needed. If all elements of the inputs are non-zero, Matt Fig's method omits half of the tests.
- In the Matlab version, the speedup of the loop is below the theoretical limit. I assume, the JIT acceleration handles the FOR loop more efficiently due to the fixed stepsize. In the MEXed version, the WHILE approach is 40% faster, which is near to the naiv expectations.
Categorías
Más información sobre Loops and Conditional Statements en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!