This question pops up quite often in one form or another (see for example here or here). So I thought I'd present it in a general form, and provide an answer which might serve for future reference.
Given an arbitrary number
n
of vectors of possibly different sizes, generate ann
-column matrix whose rows describe all combinations of elements taken from those vectors (Cartesian product) .
For example,
vectors = { [1 2], [3 6 9], [10 20] }
should give
combs = [ 1 3 10
1 3 20
1 6 10
1 6 20
1 9 10
1 9 20
2 3 10
2 3 20
2 6 10
2 6 20
2 9 10
2 9 20 ]
The
ndgrid
function almost gives the answer, but has one caveat:n
output variables must be explicitly defined to call it. Sincen
is arbitrary, the best way is to use a comma-separated list (generated from a cell array withn
cells) to serve as output. The resultingn
matrices are then concatenated into the desiredn
-column matrix:Here's a do-it-yourself method that made me giggle with delight, using
nchoosek
, although it's not better than @Luis Mendo's accepted solution.For the example given, after 1,000 runs this solution took my machine on average 0.00065935 s, versus the accepted solution 0.00012877 s. For larger vectors, following @Luis Mendo's benchmarking post, this solution is consistently slower than the accepted answer. Nevertheless, I decided to post it in hopes that maybe you'll find something useful about it:
Code:
gives
Explanation:
L
gets the lengths of each vector usingcellfun
. Althoughcellfun
is basically a loop, it's efficient here considering your number of vectors will have to be relatively low for this problem to even be practical.V
concatenates all the vectors for easy access later (this assumes you entered all your vectors as rows. v' would work for column vectors.)nchoosek
gets all the ways to pickn=length(v)
elements from the total number of elementsL(end)
. There will be more combinations here than what we need.Since there are only two elements in
v(1)
, we need to throw out any rows whereJ(:,1)>2
. Similarly, whereJ(:,2)<3
,J(:,2)>5
, etc... UsingL
andrepmat
we can determine whether each element ofJ
is in its appropriate range, and then useany
to discard rows that have any bad element.Finally, these aren't the actual values from
v
, just indices.V(J)
will return the desired matrix.A little bit simpler ... if you have the Neural Network toolbox you can simply use
combvec
:which returns a matrix in a slightly different order:
If you want the matrix that is in the question, you can use
sortrows
:which gives
If you look at the internals of
combvec
(typeedit combvec
in the command window), you'll see that it uses different code than @LuisMendo's answer. I can't say which is more efficient overall.If you happen to have a matrix whose rows are akin to the earlier cell array you can use:
I've done some benchmarking on the two proposed solutions. The benchmarking code is based on the
timeit
function, and is included at the end of this post.I consider two cases: three vectors of size
n
, and three vectors of sizesn/10
,n
andn*10
respectively (both cases give the same number of combinations).n
is varied up to a maximum of240
(I choose this value to avoid the use of virtual memory in my laptop computer).The results are given in the following figure. The
ndgrid
-based solution is seen to consistently take less time thancombvec
. It's also interesting to note that the time taken bycombvec
varies a little less regularly in the different-size case.Benchmarking code
Function for
ndgrid
-based solution:Function for
combvec
solution:Script to measure time by calling
timeit
on these functions: