Genere una matriz que contenga todas las combinaciones de elementos de n vectores (producto cartesiano)
Esta pregunta surge con bastante frecuencia de una forma u otra (ver, por ejemplo, aquí o aquí ). Así que pensé en presentarlo de forma general y proporcionar una respuesta que podría servir como referencia futura.
Dado un número arbitrario
n
de vectores de tamaños posiblemente diferentes, genere unan
matriz de columnas cuyas filas describan todas las combinaciones de elementos tomados de esos vectores (producto cartesiano).
Por ejemplo,
vectors = { [1 2], [3 6 9], [10 20] }
debería dar
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 ]
La ndgrid
función casi da la respuesta, pero tiene una advertencia: n
las variables de salida deben definirse explícitamente para llamarla. Dado que n
es arbitrario, la mejor manera es utilizar una lista separada por comas (generada a partir de una matriz de celdas con n
celdas) para que sirva como salida. Las n
matrices resultantes luego se concatenan en la n
matriz de columnas deseada:
vectors = { [1 2], [3 6 9], [10 20] }; %// input data: cell array of vectors
n = numel(vectors); %// number of vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n); %// reshape to obtain desired matrix
Un poco más simple... si tienes la caja de herramientas Neural Network, simplemente puedes usar combvec
:
vectors = {[1 2], [3 6 9], [10 20]};
combs = combvec(vectors{:}).' % Use cells as arguments
que devuelve una matriz en un orden ligeramente diferente:
combs =
1 3 10
2 3 10
1 6 10
2 6 10
1 9 10
2 9 10
1 3 20
2 3 20
1 6 20
2 6 20
1 9 20
2 9 20
Si quieres la matriz que está en la pregunta, puedes usar sortrows
:
combs = sortrows(combvec(vectors{:}).')
% Or equivalently as per @LuisMendo in the comments:
% combs = fliplr(combvec(vectors{end:-1:1}).')
lo que da
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
Si observa las partes internas de combvec
(escriba edit combvec
en la ventana de comandos), verá que usa un código diferente al de la respuesta de @LuisMendo. No puedo decir cuál es más eficiente en general.
Si tiene una matriz cuyas filas son similares a la matriz de celdas anterior, puede usar:
vectors = [1 2;3 6;10 20];
vectors = num2cell(vectors,2);
combs = sortrows(combvec(vectors{:}).')