116 views (last 30 days)

Arturo Camacho Lozano
on 23 Sep 2020 at 23:44

Commented: Arturo Camacho Lozano
on 30 Sep 2020 at 23:07

I have the following problem. Let's say I have the arrays

x = logical([0, 1, 0,0, 1,1, 0,0,0, 1,1,1, 0])

y = logical([0, 1, 1,0, 1,1, 0,1,0, 1,0,1, 0])

Array X has three intervals of 1's with indices 2:2, 5:6, and 10:12. I want to apply an "interval AND" operation to X, based on Y, in the following sense: for each interval of ones in X, if any element in Y is zero in that interval, the whole interval is zeroed, i.e., Z = intervalAND(X,Y) should be the same as

z = logical([0, 1, 0,0, 1,1, 0,0,0, 0,0,0, 0])

Let me explain. Since all(Y(2:2)) = 1, it produces ones in Z(2:2). The same happens in the second interval (5:6): Both Y(5) and Y(6) are true, producing ones in Z. However, there is a zero in Y(10:12) which zeroes the whole interval Z(10:12).

I know how to do it with a for loop:

d = diff(x);

pos = find(d == 1);

neg = find(d == -1);

z = x;

for k = 1:length(neg)

interval = pos(k)+1 : neg(k);

if ~all(y(interval))

z(interval) = false;

end

end

However, I need to vectorize it to make it run faster (I am working with huge arrays). Does someone know how to compute Z without using a for/while loop?

Bruno Luong
on 24 Sep 2020 at 6:40

Edited: Bruno Luong
on 25 Sep 2020 at 5:35

x = logical([0, 1, 0,0, 1,1, 0,0,0, 1,1,1, 0])

y = logical([0, 1, 1,0, 1,1, 0,1,0, 1,0,1, 0])

code without loop or groupping, on my bench test about 3 time faster than Stephen's accumarray solution

i = find(diff([0 x 0]));

n = histc(find(~y), i);

j = [1;-1]*(n(1:2:end)==0);

if x(end)

i(end)=[];

j(end)=[];

end

z = logical(cumsum(accumarray(i(:),j(:),[length(x),1])));

Bruno Luong
on 26 Sep 2020 at 6:01

Faster. It does not create unecessary elements to accumulate then removed.

The one before is still OK if you prefer readable code.

Mohammad Sami
on 24 Sep 2020 at 1:31

You can group based on the values of x.

gid = cumsum(x ~= circshift(x,1));

if(gid(1) == 0)

gid = gid + 1;

end

a = splitapply(@min,y,gid);

z = a(gid);

Matt J
on 25 Sep 2020 at 0:34

Using group1s from

>> xg=group1s(x)+1;

>> yg=splitapply(@all,y,xg);

>> z=yg(xg)

z =

1×13 logical array

0 1 0 0 1 1 0 0 0 0 0 0 0

Opportunities for recent engineering grads.

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

Start Hunting!
## 4 Comments

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021885

⋮## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021885

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021915

⋮## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021915

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021924

⋮## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021924

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021930

⋮## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/598801-how-to-perform-logical-and-on-intervals-of-contiguous-locations#comment_1021930

Sign in to comment.