How to find the previous position in an array where a value is met?
20 次查看(过去 30 天)
显示 更早的评论
Hi everyone,
As it is said in the title, I'd like to find the previous position(not the last position) in an array where a value is met. I have a program that works but I'm looking for improvement or optimazations of my program.
To be specific, let's suppose I have an array A=[1 0 1 0 0 0 0 1 1 1 0 0 0 0 1] and I'd like to fill in values in another array B based on values in A.
The rule is, if A(i)=1, then B(i)=1;
if A(i)=0, find the index of the previous element in A which is 1, and compute the difference between that index and current index number. If the difference is larger than 1 and no larger than 3, B(i)=2; otherwise B(i)=0;
For example, when i=5, the index of previous element in A which is 1 is 3, then 5-3=2<3, so B(5)=2; when i=7, the index of previouse element in A which is 1 is 3, then 7-3=4>3, so B(7)=0;
So in the end, I hope to have an array B=[1 0 1 0 2 2 0 1 1 1 0 2 2 0 1];
Here is what my current program looks like
A=[1 0 1 0 0 0 0 1 1 1 0 0 0 0 1];
B=NaN(length(A),1);
for i=1:length(A)
if A(i)==1
B(i)=1;
else
if i-find(B==1,1,'last')>1 && i-find(B==1,1,'last')<=3
B(i)=2;
else
B(i)=0;
end
end
end
The program works well. However the thing is, in future calculations, the length of array A could be as large as 1.5million and there will be some other calculations with indefinite amount of elements in the inner loop. So it's really time-comsuming to execute this find command in each iteration(last time I tried, it took 8hrs to compute for 500000 data points).
I tried to break the program into two one-layer-if-statements by allocating zero value to all data that satisfies the conditon in the inner loop and start another loop through them to find for which element I should specify 2 instead of 0. However, the problem is, the command find(X,n,direction) could only find the last position of an array where a value is met. So it always returns number 15 as it is the last position where value 1 appears in array A. I'm wondering, is there any other command that finds the index of the previous position where a value is met? For example, when i=5, the command would return number 3 while when i=11:14, it would return 10?
1 个评论
采纳的回答
Johannes Fischer
2019-8-28
编辑:Johannes Fischer
2019-8-28
This is an ideal playgrouond to see how you can increase speed by avoiding for loops.
% My idea is to create an array, that in each field contains the value to
% the index of the previous '1' in A. To get there, I first get the indices
% where A is 1:
A=[1 0 1 0 0 0 0 1 1 1 0 0 0 0 1];
I = 1:numel(A);
AA = I;
AA(A==0)=0;
% AA = [1 0 3 0 0 0 0 8 9 10 0 0 0 0 15];
% Now the idea is to fill the zeros in AA with the value that preceeds
% contiguous zeros to get to Last = [1 1 3 3 3 3 3 8 9 10 10 10 10 10 15];
% Im not sure this is the most efficient or easiest to understand way but
% here is the idea: use cumsum() to propagate the information of the
% previous index along the array. For that to work the array must be
% prepared such that at index 8 there is a 5 that will add up to 8 = 5+3.
% The 5 in this case also is the number of zeros +1 between the 3 and 8 in
% AA. Since the indices are linearly increasing, we can get it by taking
% diff() where AA is not equal to 0.
d = [1 diff(AA(AA~=0))];
% you did not specify what to do if A(1) is 0. My approach only works when
% A(1) is 1
% now place the values in d at the position where A is equal to 1
a = A;
a(A~=0) = d;
% and calculate the cumulative sum
Last = cumsum(a);
% To get the distance to the last '1' in A its merely
diffToLast = I-Last;
% Followed by
B = zeros(1, numel(A));
B(A==1) = 1;
B(diffToLast == 2 | diffToLast == 3) = 2;
edit: restructured added more commentary to code.
3 个评论
Johannes Fischer
2019-8-28
As I said, that case wasnt specified, but if you replace with
if A(1) == 1
d = [1 diff(AA(AA~=0))];
else
d = [find(A==1, 1, 'first') diff(AA(AA~=0))];
end
the results for B should be identical except for the values before the second '1' in A. For the others, the result assumes that A(-1) is 1.
更多回答(1 个)
darova
2019-8-28
编辑:darova
2019-8-28
clc,clear
A = randi([0 1],10,1);
% divide array into sections
ind = find(abs(diff(A))>0);
% ignore first zeros
if A(1) == 0
ind(1) = [];
end
% if last element is zero - add index
if A(end) == 0
ind(end+1) = length(A);
end
B = A;
for i = 1:2:length(ind)
i1 = ind(i)+1; % first zero in current section
i2 = ind(i+1); % last zero
if i1+0 < i2 % if second zero exists
B(i1+1) = 2; % replace 2d zero with '2'
end
if i1+1 < i2 % if third zero exists
B(i1+2) = 2; % replace 3d zero with '2'
end
end
[A B]
1 个评论
darova
2019-8-28
clc,clear
A = randi([0 1], 1, 10);
A1 = A*0;
i1 = find(A,1,'first'); % start from first '1'
for i = i1:length(A)
if A(i) == 0
k = k + 1;
else
k = 0;
end
A1(i) = k;
end
B = A;
B(A1==2 | A1==3) = 2;
[A;B]'
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Matrix Indexing 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!