11 views (last 30 days)

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?

Johannes Fischer
on 28 Aug 2019

Edited: Johannes Fischer
on 28 Aug 2019

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.

darova
on 28 Aug 2019

Something is wrong in this case. I used A = randi([0 1], 1, 10)

[A; B]'

0 0

0 2

1 2

1 2

1 2

0 2

0 0

1 2

1 2

1 2

Johannes Fischer
on 28 Aug 2019

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.

darova
on 28 Aug 2019

Edited: darova
on 28 Aug 2019

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]

Opportunities for recent engineering grads.

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

Start Hunting!
## 1 Comment

## Direct link to this comment

https://de.mathworks.com/matlabcentral/answers/477866-how-to-find-the-previous-position-in-an-array-where-a-value-is-met#comment_739698

⋮## Direct link to this comment

https://de.mathworks.com/matlabcentral/answers/477866-how-to-find-the-previous-position-in-an-array-where-a-value-is-met#comment_739698

Sign in to comment.