问题
I want to find the lengths of all series of ones and zeros in a logical array in MATLAB. This is what I did:
A = logical([0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1]);
%// Find series of ones:
csA = cumsum(A);
csOnes = csA(diff([A 0]) == -1);
seriesOnes = [csOnes(1) diff(csOnes)];
%// Find series of zeros (same way, using ~A)
csNegA = sumsum(~A);
csZeros = csNegA(diff([~A 0]) == -1);
seriesZeros = [csZeros(1) diff(csZeros)];
This works, and gives seriesOnes = [4 2 5]
and seriesZeros = [3 1 6]
. However it is rather ugly in my opinion.
I want to know if there is a better way to do this. Performance is not an issue as this is inexpensive (A
is no longer than a few thousand elements). I am looking for code clarity and elegance.
If nothing better can be done, I'll just put this in a little helper function so I don't have to look at it.
回答1:
You could use an existing code for run-length-encoding, which does the (ugly) work for you and then filter out your vectors yourself. This way your helper function is rather general and its functionality is evident from the name runLengthEncode
.
Reusing code from this answer:
function [lengths, values] = runLengthEncode(data)
startPos = find(diff([data(1)-1, data]));
lengths = diff([startPos, numel(data)+1]);
values = data(startPos);
You would then filter out your vectors using:
A = logical([0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1]);
[lengths, values] = runLengthEncode(A);
seriesOnes = lengths(values==1);
seriesZeros = lengths(values==0);
回答2:
You can try this:
A = logical([0 0 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1]);
B = [~A(1) A ~A(end)]; %// Add edges at start/end
edges_indexes = find(diff(B)); %// find edges
lengths = diff(edges_indexes); %// length between edges
%// Separate zeros and ones, to a cell array
s(1+A(1)) = {lengths(1:2:end)};
s(1+~A(1)) = {lengths(2:2:end)};
回答3:
This strfind (works wonderfully with numeric arrays as well as string arrays) based approach could be easier to follow -
%// Find start and stop indices for ones and zeros with strfind by using
%// "opposite (0 for 1 and 1 for 0) sentients"
start_ones = strfind([0 A],[0 1]) %// 0 is the sentient here and so on
start_zeros = strfind([1 A],[1 0])
stop_ones = strfind([A 0],[1 0])
stop_zeros = strfind([A 1],[0 1])
%// Get lengths of islands of ones and zeros using those start-stop indices
length_ones = stop_ones - start_ones + 1
length_zeros = stop_zeros - start_zeros + 1
来源:https://stackoverflow.com/questions/28791773/find-number-of-consecutive-ones-in-binary-array