Juergen
Juergen

Reputation: 3743

Counting values of one vector that lie in between the values of another vector

Say we have two ascending sorted vectors:

V1 V2
12 13
15 16
25 17
29 28

What is the simplest way in Matlab to count how many values of V2 fall between consecutive values of V1?

In this example the resulting vector should be:

Counts
1
2
1

since

1 - 13(V2) fits between 12-15(V1)

2 - 16 and 17(V2) fits between 15-25(V1)

1 - 28(V2) fits between 25-29(V1)

Upvotes: 1

Views: 66

Answers (5)

Luis Mendo
Luis Mendo

Reputation: 112689

I can't believe that nobody has thought of histc yet:

count = histc(v2,v1);

gives, in this case

count =
     1 %// 1 value  of v2 is  >= v1(1) and < v1(2)
     2 %// 2 values of v2 are >= v1(2) and < v1(3)
     1 %// 1 value  of v2 is  >= v1(3) and < v1(4)
     0 %// 0 values of v2 are == v1(4)

Upvotes: 4

Anoop
Anoop

Reputation: 5720

>> v1 = [12    ;15    ;25    ;29];
>> v2 = [13    ;16    ;17    ;28];
>> diff(find(ismember(sort([v1 ;v2]),v1) == 1))  - 1
ans =

     1     
     2     
     1

magic!! without loops!!

But the logic is quiet easy to understand

Using row vectors instead of column vectors as an example

I first create a sorted list of combination of v1, v2 so

>> v3 = sort([v1 v2])

v3 =

    12    13    15    16    17    25    28    29

Then this is the key step, I make members of v1 as 1 in v4 and the rest 0. Like this

>> v4 = ismember(v3,v1)

v4 =

     1     0     1     0     0     1     0     1

At this point, the problem is almost solved, I need to find the groups of zeros and thier length

>> diff(find(v4 == 1)) - 1

ans =

     1     2     1

No loops, less time to run.

Upvotes: 1

chappjc
chappjc

Reputation: 30579

bsxfun can do all the tests you need, then you can vectorize the combination with & (element-wise AND), and sum:

>> low = bsxfun(@lt,V1,V2.');    %' each row of V1 < each row of V2
>> high = bsxfun(@gt,V1,V2.');   %' each row of V1 > each row of V2
>> sum(low(1:end-1,:) & high(2:end,:),2)
ans =
     1
     2
     1

NOTE: To check >= instead of >, use @ge (instead of @gt). Similarly for <= and <, use @le or @lt.

Upvotes: 1

Mathias
Mathias

Reputation: 1500

I think this works without loops:

V1 = [12 15 25 29]';
V2 = [13 16 17 28]';


V3 = [V1 zeros(size(V1)); V2 ones(size(V2))];
V4 = sortrows(V3);

ret = diff(find(V4(:,2)==0))-1

This first creates the Vector

V3 =

   12    0
   15    0
   25    0
   29    0
   13    1
   16    1
   17    1
   28    1

Then sorts it

V4 =

   12    0
   13    1
   15    0
   16    1
   17    1
   25    0
   28    1
   29    0

Now the position of the zeros mark the next entry in V1. find finds those positions and diff substracts the positions, leaving the numbers from V2 between them plus one.

Upvotes: 1

ivanibash
ivanibash

Reputation: 1491

V1 = [12,15,25,29];
V2 = [13,16,17,28];
V3 = zeros(1,length(V1)-1);
count = 0;

for i = 1:length(V1)-1
    for k = 1:length(V2)
        if(V2(k)>V1(i) && V2(k)<V1(i+1))
            count = count+1;
        end

    end
    V3(i) = count;
    count = 0;
end

V3

Upvotes: 0

Related Questions