Counting x times zeros in a row on a given sequence

4 views (last 30 days)
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.

Answers (4)

Jan
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))

DGM
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?
runsfound = 12
Adjust as needed.
  3 Comments
DGM
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
A = 1×15
1 2 1 1 2 2 2 0 0 0 2 1 0 2 1
dA = [true diff(A) ~= 0] % logical vector describing where A is changing
dA = 1×15 logical array
1 1 1 0 1 0 0 1 0 0 1 1 1 1 1
dAidx = find([dA true]) % indices where dA is true
dAidx = 1×11
1 2 3 5 8 11 12 13 14 15 16
RL = diff(dAidx) % first derivative of index list (the length of each run)
RL = 1×10
1 1 2 3 3 1 1 1 1 1
values = A(dA) % the value of A associated with each run
values = 1×10
1 2 1 2 0 2 1 0 2 1
zeroRLs = RL(values==0) % length of each run of zeros
zeroRLs = 1×2
3 1
onesRLs = RL(values==1) % length of each run of ones
onesRLs = 1×4
1 2 1 1
twosRLs = RL(values==2) % length of each run of twos
twosRLs = 1×4
1 3 1 1
Then the last bit simply finds the number of instances where zeroRLs has a specific number in it.
DGM
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
numblocksfound = 15

Sign in to comment.


Image Analyst
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
Eleftherios Karampasis
Eleftherios Karampasis on 31 Oct 2021
Thank you for your time and effort in aswering my question. I should had pointed out that I am a beginner in Matlab and as so I am obliged to use the simplest commands availble even at the expanse of time and practicality. To be honest I am not familiar with these commands and so I cant use them without realisng more simple command first. I appologize if my ignorance spoled your time.
Image Analyst
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.

Sign in to comment.


Matt J
Matt J on 31 Oct 2021
Edited: Matt J on 31 Oct 2021
Using,
x=randi([0,1],1,1e7); %random sequence
[~,~,runlengths]=groupLims(groupTrue(~x),1);
count=sum(runlengths==10) %number of sequences with length=10

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!