Générer toutes les combinaisons possibles des éléments de certains vecteurs (produit Cartésien)

je tiens à générer toutes les combinaisons possibles des éléments d'un certain nombre de vecteurs.

Par exemple, pour [1 2] , [1 2] et [4 5] je veux générer les éléments:

[1 1 4; 1 1 5; 1 2 4; 1 2 5; 2 1 4; 2 1 5; 2 2 4; 2 2 5]

le problème est que je ne sais pas le nombre de vecteurs pour lesquels je dois calculer les combinaisons. Il pourrait y en avoir 3 comme dans ce cas, ou il pourrait y en avoir 10, et j'ai besoin d'un généralisation . Tu peux m'aider à faire ça à MATLAB? Il y a déjà une fonction prédéfinie qui peut faire cette tâche?

32
demandé sur chappjc 2010-11-12 17:56:42

4 réponses

Essayer ALLCOMB fonction à FileExchange.

si vous stockez vos vecteurs dans un tableau de cellules, vous pouvez l'exécuter comme ceci:

a = {[1 2], [1 2], [4 5]};
allcomb(a{:})
ans =

     1     1     4
     1     1     5
     1     2     4
     1     2     5
     2     1     4
     2     1     5
     2     2     4
     2     2     5
16
répondu yuk 2010-11-12 16:07:07

envisager cette solution en utilisant la NDGRID fonction:

sets = {[1 2], [1 2], [4 5]};
[x y z] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:)];

cartProd =
     1     1     4
     2     1     4
     1     2     4
     2     2     4
     1     1     5
     2     1     5
     1     2     5
     2     2     5

ou si vous voulez une solution générale pour n'importe quel nombre d'ensembles (sans avoir à créer les variables manuellement), utilisez cette définition de fonction:

function result = cartesianProduct(sets)
    c = cell(1, numel(sets));
    [c{:}] = ndgrid( sets{:} );
    result = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
end

Notez que si vous préférez, vous pouvez trier les résultats:

cartProd = sortrows(cartProd, 1:numel(sets));

aussi, le code ci-dessus ne vérifie pas si les ensembles n'ont pas de duplicata valeurs (ex: {[1 1] [1 2] [4 5]} ). Ajouter cette ligne si vous voulez:

sets = cellfun(@unique, sets, 'UniformOutput',false);
47
répondu Amro 2010-11-12 22:06:27

ces réponses tardives offrent deux solutions supplémentaires, dont la seconde est la solution (à mon avis) et une amélioration de la solution de réponse D'Amro avec ndgrid en appliquant les puissantes listes séparées par des virgules de MATLAB au lieu de réseaux cellulaires pour une haute performance,

  1. si vous avez la boîte à outils du réseau neuronal: utiliser combvec
  2. si vous faites Non ont la boîte à outils, comme est généralement le cas: ci-dessous est une autre façon de généraliser le produit cartésien pour un certain nombre d'ensembles.

tout comme Amro dans sa réponse, la syntaxe des listes séparées par des virgules ( v{:} ) fournit à la fois les entrées et les sorties de ndgrid . La différence (quatrième ligne) est qu'il évite cellfun et cell2mat en appliquant des listes séparées par des virgules, encore une fois, maintenant que les entrées à cat :

N = numel(a);
v = cell(N,1);
[v{:}] = ndgrid(a{:});
res = reshape(cat(N+1,v{:}),[],N);

L'utilisation de cat et reshape réduit le temps d'exécution de presque la moitié. Cette approche a été démontrée dans ma réponse à une question différente , et plus formellement par Luis Mendo .

11
répondu chappjc 2017-05-23 10:31:06

nous pouvons également utiliser l'instruction 'combvec' dans matlab

    no_inp=3 % number of inputs we want...in this case we have 3 inputs                  
    a=[1 2 3]
    b=[1 2 3]
    c=[1 2 3]

    pre_final=combvec(c,b,a)';
    final=zeros(size(pre_final));

    for i=1:no_inp
    final(:,i)=pre_final(:,no_inp-i+1);
    end
    final 

J'espère que ça aidera. Bonne chance.

0
répondu Akhil Appu Shetty 2018-01-13 20:40:35