在二进制数组中查找连续的个数
Find number of consecutive ones in binary array
我想在 MATLAB 中找到逻辑数组中所有 1 和 0 序列的长度。这就是我所做的:
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)];
这有效,并给出 seriesOnes = [4 2 5]
和 seriesZeros = [3 1 6]
。不过在我看来还是比较丑的。
我想知道是否有更好的方法来做到这一点。性能不是问题,因为它很便宜(A
不超过几千个元素)。我正在寻找代码清晰和优雅。
如果没有更好的办法,我就把它放在一个小辅助函数中,这样我就不用看它了。
这种基于 strfind
(非常适用于数字数组和字符串数组)的方法可能更容易理解 -
%// 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
您可以使用 运行-length-encoding 的现有代码,它为您完成(丑陋的)工作,然后您自己过滤掉您的向量。这样你的辅助函数就相当通用了,它的功能从名字 runLengthEncode
.
就可以看出。
重用来自 this answer 的代码:
function [lengths, values] = runLengthEncode(data)
startPos = find(diff([data(1)-1, data]));
lengths = diff([startPos, numel(data)+1]);
values = data(startPos);
然后您将使用以下方法过滤掉您的向量:
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);
你可以试试这个:
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)};
我想在 MATLAB 中找到逻辑数组中所有 1 和 0 序列的长度。这就是我所做的:
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)];
这有效,并给出 seriesOnes = [4 2 5]
和 seriesZeros = [3 1 6]
。不过在我看来还是比较丑的。
我想知道是否有更好的方法来做到这一点。性能不是问题,因为它很便宜(A
不超过几千个元素)。我正在寻找代码清晰和优雅。
如果没有更好的办法,我就把它放在一个小辅助函数中,这样我就不用看它了。
这种基于 strfind
(非常适用于数字数组和字符串数组)的方法可能更容易理解 -
%// 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
您可以使用 运行-length-encoding 的现有代码,它为您完成(丑陋的)工作,然后您自己过滤掉您的向量。这样你的辅助函数就相当通用了,它的功能从名字 runLengthEncode
.
重用来自 this answer 的代码:
function [lengths, values] = runLengthEncode(data)
startPos = find(diff([data(1)-1, data]));
lengths = diff([startPos, numel(data)+1]);
values = data(startPos);
然后您将使用以下方法过滤掉您的向量:
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);
你可以试试这个:
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)};