How can I access multiples areas in one array without using a for-loop?

I have a array A with 20 000 000 x 1 elements, and two vectors b & c with 500000x1 elements each. now I want to set the areas form b(1:500000):c(1:500000) to zero. I can write it with a for loop but this takes very long:
if true
for i=1:size(b,1)
A(b(i):c(i))=0;
end
end
Thats why I thought I can use:
if true
A(b:c)=0;
end
but it sets only A(b(1):c(1)) to zero and ignores the other elements of the vector.
do you know a fast fucntion to acess the areas at once? Thanks!

8 commentaires

jonas
jonas le 24 Juil 2018
Modifié(e) : jonas le 24 Juil 2018
Could you show with a small example what you have in A, b and c as well as the desired output? From the for loop it seems that you have 500k intervals of data that you want to target, where interval i is from a(i) to b(i)
Is that correct?
Do we need to be concerned with overlap? For example b(5) = 11, c(5) = 15, b(19) = 14, c(19) = 16 would have the same effect as b(5) = 11, c(5) = 16
Thanks for the answer: A varies from -1 to 1 and could be for example 0.1101 or -0.8934. the first values from b are 159; 255; 359; 431; 567; ... the first values from c are 160; 258; 400; 433; 605; ... No there is no overlap. The numbers are increasing .
How are b and c created? As I answered, I don't think that there is a way to make your code faster once you have b and c but it may be possible to improve the code before that to create something easier to work with (e.g. a logical array)
if true
%A(:,1) are nubmers between -1 and 1
%A(:,2) is empty and will be filled later
%A(:,3) is -1 if A(:,1)<1; 0 if A(:,1) = 0 and 2 if A(:,1) > 0
Diff = diff(A(:,3)); %calculate diff and find changes of PRL
Diffrows = find(Diff)+1;
DiffTime = [diff(Diffrows);size(A(:,3),1)-Diffrows(end,1)]; %Time
between changes
if DiffTime(end) ==0 % if Duration is 0
DiffTime(end)= 1;
end
A(Diffrows,4)=DiffTime;
%Identify changes
rowindex=find(abs(Diff)==3)+1; %find changes from pos to neg or neg to pos
if ~isempty(rowindex) %if not empty
duration=A(rowindex,4); %add duration values to changes
for k = 1: size(rowindex2,1)
A(rowindex2(k):(rowindex2(k)+duration(k))-1,1:3)=0;
end
end
end
This is the code but it is not really nice to read
Guillaume
Guillaume le 24 Juil 2018
Modifié(e) : Guillaume le 24 Juil 2018
So if I understand correctly, you want to set to 0 all the positive values when A changes from negative to positive without passing through 0 and all the negative values when A changes from positive to negative without passing through 0?
Also, A(:, 3) is the sign of A(:, 1) except you're using 2 instead of 1 for positive values. Any reason for that 2?
Also, note that your last DiffTime, if not 0, is calculated incorrectly. You should always add 1, so your
if DiffTime(end) ==0 % if Duration is 0
DiffTime(end)= 1;
end
should be replaced by
DiffTime(end) = DiffTime(end) + 1;
or even better, get it right in the first place with:
DiffTime = [diff(Diffrows); size(A, 1)-Diffrows(end,1)+1]; %no need for further adjustment.
Note that size(A(:, 3), 1) is simply size(A, 1)
Yes correct. I use 2 because I want to detect next to the change from negativ to positv and postiv to negativ if it changes from zero to positiv or zero to negativ and not if it changes from positv to zero or negativ to zero. So it is easier with 2. Thanks for the changes to DiffTime. I will add this correctly in the first place!

Connectez-vous pour commenter.

 Réponse acceptée

This probably does what you want:
%A a vector
signchange = [0; diff(sign(A))]; %find sign changes in A
transitions = find(signchange); %index where the sign change occur
%the next few lines fill the 0s of the sign change by the previous non-zero values
rows = 1:numel(A);
g = griddedInterpolant(rows(transitions), signchange(transitions), 'previous');
tofill = ~signchange;
signchange(tofill) = g(rows(tofill));
%now any absolute value in signchange of 2 is the run of values to set to 0
A(abs(signchange) == 2) = 0;
The trick of using griddedInterpolant to propagate values comes from the fillmissing.m code.

Plus de réponses (1)

With arrays that size, the fastest is probably the loop you have written.
With smaller arrays, you could do:
indices = 1:numel(A);
tozero = any(indices > a(:) & indices < b(:)); %assuming R2016b or later for implicit expansion
A(tozero) = 0;
However, that requires a temporary 20000000 x 500000 array which would take over 745 GB of memory.

1 commentaire

Thanks! I wasn't sure if there is a faster and better way to solve it but it seems not.

Connectez-vous pour commenter.

Catégories

Community Treasure Hunt

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

Start Hunting!

Translated by