How to generate all pairs from two vectors in MATLAB using vectorised code?
Asked Answered
S

9

49

More than once now I have needed to generate all possible pairs of two vectors in MATLAB which I do with for loops which take up a fair few lines of code i.e.

vec1 = 1:4;
vec2 = 1:3;
i = 0;
pairs = zeros([4*3 2]);
for val1 = vec1
    for val2 = vec2
         i = i + 1;
         pairs(i,1) = val1;
         pairs(i,2) = val2;
    end
end

Generates ...

1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 1 
4 2
4 3

There must be a better way to do this which is more MATLAB'esque?

n.b. nchoosek does not do the reversed pairs which is what I need (i.e. 2 1 as well as 1 2), I can't just reverse and append the nchoosek output because the symmetric pairs will be included twice.

Snowdrop answered 16/9, 2011 at 15:26 Comment(1)
possible duplicate of Matlab - Generate all possible combinations of the elements of some vectorsUhland
S
97

Try

[p,q] = meshgrid(vec1, vec2);
pairs = [p(:) q(:)];

See the MESHGRID documentation. Although this is not exactly what that function is for, but if you squint at it funny, what you are asking for is exactly what it does.

Satanism answered 16/9, 2011 at 15:26 Comment(1)
That's brilliant. I knew both meshgrid and serialising of 2d vectors but never considered using them in this way.Snowdrop
W
13

You may use

a = 1:4;
b = 1:3;
result = combvec(a,b);
result = result'
Walloon answered 12/5, 2014 at 14:35 Comment(3)
Note that this requires the Neural Network toolbox. For those who have it it seems to be the best solution.Triste
Like this better than the accepted solution, as it generalizes to multiple vectors.Cysticercus
@neuronet A late reply I know, but it's worth future visitors knowing that this is very slow compared to the accepted solution for large vectors.Metallophone
A
4

You could do it by replicating the matrices using repmat and then turning the result into a column vector using reshape.

a = 1:4;
b = 1:3;
c = reshape( repmat(a, numel(b), 1), numel(a) * numel(b), 1 );
d = repmat(b(:), length(a), 1);
e = [c d]

e =

     1     1
     1     2
     1     3
     2     1
     2     2
     2     3
     3     1
     3     2
     3     3
     4     1
     4     2
     4     3

Of course, you can get rid of all the intermediate variables from the example above.

Arianearianie answered 16/9, 2011 at 15:37 Comment(0)
O
3

Another solution for collection:

[idx2, idx1] = find(true(numel(vec2),numel(vec1)));
pairs = [reshape(vec1(idx1), [], 1), reshape(vec2(idx2), [], 1)];
Olivaolivaceous answered 9/4, 2013 at 16:42 Comment(3)
+1: I've deleted my solution, I like yours better. I've taken the liberty to correct it though, to obtain the combinations of vec1 and vec2.Wilterdink
@EitanT: No need to reshape. Indices from find always should be column vectors, as well as vec1(idx1) etc.Olivaolivaceous
I think that reshaping is necessary. Given that idx1 is a vector (doesn't matter if row or column), if vec1 is a row vector then vec1(idx1) will also be a row vector. The same goes for vec2.Wilterdink
O
2

What you are looking for is the cartesian product

cartprod is the function that implements it. You can find it in the linear-algebra package so you would need to do:

   >> pkg install -forge linear-algebra
   >> pkg load linear-algebra 
   >> sortrows(cartprod(1:4,1:3))                                            
    ans =                                                                                           
       1   1                                                                  
       1   2                                                                  
       1   3                                                                  
       2   1                                                                  
       2   2                                                                  
       2   3                                                                  
       3   1                                                                  
       3   2                                                                  
       3   3                                                                  
       4   1                                                                  
       4   2                                                                  
       4   3    
Opportina answered 11/4, 2016 at 19:32 Comment(1)
For what it's worth, a function claiming to do the same thing is also available on the MATLAB File exchange.Illuminati
I
2

You can use plain old matrix operations, e.g. in

x = [3,2,1];
y = [11,22,33,44,55];
v = [(ones(length(y),1) * x)(:), (ones(length(x), 1) * y)'(:)]

Edit: this is Octave syntax, MATLAB will look like this:

x = [3,2,1];
y = [11,22,33,44,55];
A = ones(length(y),1) * x;
B = (ones(length(x), 1) * y)';
v = [A(:) B(:)]

in both cases, result will be

v =
 3    11
 3    22
 3    33
 3    44
 3    55
 2    11
 2    22
 2    33
 2    44
 2    55
 1    11
 1    22
 1    33
 1    44
 1    55
Illconsidered answered 23/5, 2017 at 20:59 Comment(1)
That's not valid MATLAB syntax.Inherit
P
2

As of MATLAB R2023a, you can use the combinations function to do this. Details at https://blogs.mathworks.com/matlab/2023/04/04/the-new-combinations-function-in-matlab-for-cartesian-products-and-parameter-sweeps/

> A = [1,2,3];B=[4,5];
>> C = combinations(A,B)
C =
6×2 table
A    B
_    _
1    4
1    5
2    4
2    5
3    4
3    5

The result is a table. When all data types are compatible (as is the case here) you can get the matrix like this

>> C.Variables
ans =
1     4
1     5
2     4
2     5
3     4
3     5
Pantheism answered 4/4, 2023 at 10:4 Comment(0)
P
1

Here a more MATLAB'esque way to find the combinations. This one can also be easily extended to more then 2 vectors (and also non-numerical combinations):

v1 =   1:  1:  3;
v2 =  11: 11: 44;
v3 = 111:111:555;

dimensions = cellfun(@numel, {v1,v2,v3});

[i1,i2,i3] = ind2sub(dimensions, 1:prod(dimensions));

combinations = [v1(i1); v2(i2); v3(i3)]'
Poundage answered 24/5, 2016 at 13:14 Comment(0)
I
1

Starting from version R2015a, you can do this using repelem and repmat:

>> vec1 = 1:4;
>> vec2 = 1:3;
>> pairs = [repelem(vec1(:), numel(vec2)) ...
            repmat(vec2(:), numel(vec1), 1)]

pairs =

     1     1
     1     2
     1     3
     2     1
     2     2
     2     3
     3     1
     3     2
     3     3
     4     1
     4     2
     4     3

This type of solution avoids the additional intermediate variables required by some of the other solutions (such as those based on meshgrid) which could lead to memory issues for larger vectors.

Inherit answered 24/6, 2019 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.