web-dev-qa-db-fra.com

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

Je voudrais générer toutes les combinaisons possibles des éléments d'un nombre donné de vecteurs.

Par exemple, pour [1 2], [1 2] et [4 5], je souhaite 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 connais pas le nombre de vecteurs pour lesquels je dois calculer les combinaisons. Il peut y en avoir 3 comme dans ce cas, ou il peut y en avoir 10, et j’ai besoin d’une généralisation. Pouvez-vous m'aider s'il vous plaît à cela dans MATLAB? Existe-t-il déjà une fonction prédéfinie pouvant effectuer cette tâche?

32
Simon

Essayez ALLCOMB function à FileExchange.

Si vous stockez des vecteurs dans un tableau de cellules, vous pouvez l'exécuter comme suit:

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
yuk

Considérez cette solution en utilisant la fonction NDGRID :

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 souhaitez une solution générale pour un nombre quelconque 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));

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

sets = cellfun(@unique, sets, 'UniformOutput',false);
47
Amro

Cette réponse tardive fournit deux solutions supplémentaires, la seconde étant la solution (à mon avis) et une amélioration de la solution de réponse d'Amro avec ndgrid en appliquant les puissantes listes MATLAB séparées par des virgules au lieu de tableaux de cellules pour des performances élevées

  1. Si vous avez la boîte à outils Neural Network: utilisez combvec
  2. Si vous avez pas _ avez la boîte à outils, comme d'habitude: voici un autre moyen de généraliser le produit cartésien pour un nombre quelconque d'ensembles.

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) réside dans le fait qu’elle évite cellfun et cell2mat en appliquant des listes séparées par des virgules, là encore, en tant qu’entrées dans 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 près de moitié. Cette approche a été démontrée dans ma réponse à une question différente , et plus formellement de Luis Mendo .

11
chappjc

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 vous aidera ... Bonne chance.

0
Akhil Appu Shetty