Reputation: 431
How to identify first occurrence of at least 10 adjacent '1's in a vector starting from 1st element which is composed of zeros and ones only?
A=[0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1]
The code should return index of A (12 in this example), where series of 1's start.
Upvotes: 3
Views: 182
Reputation: 4269
Isn't the kind of "memory-intensive" solution faster? (Can't check here, don't have Matlab any more :´( )
A = [0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1];
len_A = length(A);
helper = repmat(A,10,2);
helper = helper(bsxfun(@plus,bsxfun(@plus,(0:10-1)',0:len_A-1)*10,(1:10)'));
result = find(all(helper(:,1:end-10)),1)
EDIT: What about:
helper = cumsum(A);
result = 1 + find(helper - [helper(11:end) nan(1,10)]==-10,1)
should be quite good too
Upvotes: 1
Reputation: 14939
Summary: Loops beat arrayfun
by a mile!
Here's a way to do it using a classic old loop:
function x = test_loop(A)
for ii = 1:numel(A)-9
x = ii*(all(A(ii:ii+9)));
if x
break;
end
end
end
Now, let's investigate the performance of arrayfun
vs classic for
-loops:
The arrayfun approach:
test_array = @(A)find(arrayfun(@(x) all(A(x:x+9)==ones(1,10)), 1:numel(A)-9)==1,1)
A = [0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1];
B = repmat(A,1,10); %% 1x300 array
f = @() test_array(A);
g = @() test_loop(A);
Benchmarking results for your array (1x30):
timeit(f)
ans =
2.1397e-04
timeit(g)
ans =
2.6224e-05
Benchmarking results for array of size 1x300:
f = @() test_array(B);
g = @() test_loop(B);
timeit(f)
ans =
0.0021
timeit(g)
ans =
2.6598e-05
If the first sequence of is found late in the vector, the loop will be a bit slower, but still way faster than arrayfun:
B(1:220) = 0;
f = @() test_array(B);
g = @() test_loop(B);
timeit(f)
ans =
0.0021
timeit(g)
ans =
4.5033e-04
Edit:
Why increment the counter by 1 for every iteration? The following loop is approximately twice as fast as the for loop, depending on where the sequence appear in the vector, and the spacing between the zeros.
It's still slower that conv
, but thought it was worth sharing anyway:
function x = test_loop(A)
ii = 1;
x = false;
while ~x
k = find(A(ii:ii+9)~=1, 1, 'last');
x = isempty(k)*ii;
ii = ii + k;
end
end
Upvotes: 5
Reputation: 4549
Possible solution using diff and find:
temp = diff([0 A 0]);
start = find(temp == 1);
finish = find(temp == -1);
result = start(find(finish - start >= 10, 1, 'first'));
Upvotes: 2
Reputation: 112659
You could use a regexp:
A = [0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1];
N = 10;
result = regexp(char(A+'0'), ['1{' num2str(N) '}'], 'once');
Or convolution:
A = [0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1];
N = 10;
result = find(conv(2*A-1, ones(1,N), 'valid')==N, 1)
Upvotes: 3
Reputation: 8566
you can use arrayfun
to do Matlab-style "array comprehension":
A=[0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 0 1]
b = arrayfun(@(x) all(A(x:x+9)==ones(1,10)), 1:numel(A)-9)
find(b==1)
Upvotes: 3