Counting x times zeros in a row on a given sequence
4 views (last 30 days)
Show older comments
I would like to create an algorithm that generates random sequences of 0 and 1 and in the end will be able to calculate how many times there are 10 zeros in a row for a sequence of 0 and 1 up to 1 million.
0 Comments
Answers (4)
Jan
on 31 Oct 2021
Edited: Jan
on 31 Oct 2021
The question is not uniquely clear yet: What is the wanted answer for e.g. 20 subsequent zeros? Should the be counted as 1, 2 or 11 occurences?
There is no need for external functions or the Image Processing Toolbox.
1. If the overlap does not matter, such that 20 zeros are counted as 11 occurences:
% Method 1:
x = randi([0, 1], 1, 1e6);
num = numel(strfind(x, zeros(1, 10)));
2. If you want to count a sequence of more than 10 zeros as 1 occurence:
% Method 2a:
d = [true, diff(x) ~= 0]; % TRUE if values change
b = x(d); % Elements without repetitions
k = find([d, true]); % Indices of changes
n = diff(k); % Number of repetitions
num = sum(n >= 10 & b == 0)
Or:
% Method 2b:
padx = [1, x, 1]; % Padding to catch 0 on the margins
ini = strfind(padx, [1, 0]); % Start of the sequence
fin = strfind(padx, [0, 1]); % End of the sequence
n = fin - ini; % Length
num = sum(n >= 10)
3. If you want to count 20 zeros as 2 occurences of a block of 10 zeros, use one of the two methods above and replace n>=10 by floor(n / 10) :
% Method 3a (based on 2a, but last line is):
num = sum(floor(n / 10) * (b == 0))
This is a bit tricky: b==0 is converted to 1 if the comparison is TRUE, otherwise it is 0. To count e.g. 21 subsequent zeros as 2 blocks, divide it by 10, and multiply it by the comparison.
% Method 3b (based on 2b, but last line is):
num = sum(floor(n / 10))
0 Comments
DGM
on 31 Oct 2021
Edited: DGM
on 31 Oct 2021
A = randi([0 1],1,1E3); % random vector of ones,zeros
dA = [true diff(A) ~= 0]; % logical vector describing where A is changing
dAidx = find([dA true]); % indices where dA is true
RL = diff(dAidx); % first derivative of index list (the length of each run)
zeroRLs = RL(A(dA)==0); % length of each run of zeros
RLspec = 5; % what size of run are you looking for?
runsfound = nnz(zeroRLs==RLspec) % how many runs are exactly that length?
Adjust as needed.
3 Comments
DGM
on 31 Oct 2021
These are some of the most basic functions:
- diff(): difference of adjacent elements (approximate derivative)
- find(): find indices of nonzero elements
- nnz(): number of nonzero elements
The rest is just simple concatenation [] and logical operators (==, ~=).
Consider a further generalization:
A = randi([0 2],1,15) % random vector of zeros, ones, twos
dA = [true diff(A) ~= 0] % logical vector describing where A is changing
dAidx = find([dA true]) % indices where dA is true
RL = diff(dAidx) % first derivative of index list (the length of each run)
values = A(dA) % the value of A associated with each run
zeroRLs = RL(values==0) % length of each run of zeros
onesRLs = RL(values==1) % length of each run of ones
twosRLs = RL(values==2) % length of each run of twos
Then the last bit simply finds the number of instances where zeroRLs has a specific number in it.
DGM
on 31 Oct 2021
...
A = randi([0 1],1,1E3); % random vector of ones,zeros
targetbs = 5; % target block size
numblocksfound = 0;
bs = 0;
A = [A 1];
for k = 1:numel(A)
if ~A(k)
% if this element is zero, increment current block size measurement
bs = bs + 1;
else
% if this element is not zero, the run is over
% check to see if the block is the desired length
if bs == targetbs
numblocksfound = numblocksfound + 1;
end
bs = 0;
end
end
numblocksfound
Image Analyst
on 31 Oct 2021
If you have the Image Processing Toolbox, you can use the functions that are meant for this kind of thing. I present 3 different methods for getting the answer.
v = randi([0, 1], 1, 1E6); % Random vector of one million ones and zeros.
% Method 1 : using regionprops
% Measure lengths of runs of zeros. Need to invert the vector.
props = regionprops(logical(~v), 'Area')
% Get all the lengths
allLengths = [props.Area];
% Count the number that are exactly 10 elements long, no less and no more.
num10 = sum(allLengths == 10)
% Method 2 : using bwareafilt and bwlabel
v2 = bwareafilt(~v, [10, 10]); % Extract only runs that are 10 long.
[~, num10] = bwlabel(v2) % Count them
% Method 3 : using bwareafilt and nnz
v2 = bwareafilt(~v, [10, 10]); % Extract only runs that are 10 long.
num10 = nnz(v2)/10 % Count them
You can time them all with tic and toc if speed is important to you.
2 Comments
Image Analyst
on 31 Oct 2021
Well certainly
v2 = bwareafilt(~v, [10, 10]); % Extract only runs that are 10 long.
num10 = nnz(v2)/10 % Count them
is the simplest possible at only 2 lines of code. Basically it finds all runs of all lengths, and then looks at the min and max length you put in. I put in [10,10] so it only will extract runs of length 10 alone. All other lengths are filtered out.
Then nnz counts the number of non-zero elements. So if v2 had 2 runs of 10, there will be 20 elements with 1 (right at the location where there were zeros in the original vector). So then we simply divide by the length of the runs (10) and we'd get 2 runs.
Now you're familiar with those functions. So now you can use them.
See Also
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!