web-dev-qa-db-fra.com

Comment générer toutes les paires à partir de deux vecteurs dans MATLAB en utilisant du code vectorisé?

Plus d'une fois maintenant, j'ai eu besoin de générer toutes les paires possibles de deux vecteurs dans MATLAB que je fais avec pour les boucles qui occupent quelques lignes de code, c'est-à-dire.

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

Génère ...

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

Il doit y avoir une meilleure façon de le faire qui est plus MATLAB'esque?

n.b. nchoosek ne fait pas les paires inversées, c'est ce dont j'ai besoin (c'est-à-dire 2 1 aussi bien que 1 2), Je ne peux pas simplement inverser et ajouter la sortie nchoosek car les paires symétriques seront incluses deux fois.

46
Brendan

Essayer

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

Voir la documentation MESHGRID . Bien que ce ne soit pas exactement à quoi sert cette fonction, mais si vous plissez les yeux à ce sujet, ce que vous demandez, c'est exactement ce qu'il fait.

91
Lambdageek

Vous pouvez utiliser

a = 1:4;
b = 1:3;
result = combvec(a,b);
result = result'
12
efirvida

Vous pouvez le faire en répliquant les matrices en utilisant repmat puis en transformant le résultat en un vecteur de colonne en utilisant 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

Bien sûr, vous pouvez vous débarrasser de toutes les variables intermédiaires de l'exemple ci-dessus.

3
Praetorian

Une autre solution pour la collecte:

[idx2, idx1] = find(true(numel(vec2),numel(vec1)));
pairs = [reshape(vec1(idx1), [], 1), reshape(vec2(idx2), [], 1)];
3
yuk

Vous pouvez utiliser des opérations matricielles simples, par exemple dans

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

Edit: c'est la syntaxe Octave, MATLAB ressemblera à ceci:

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(:)]

dans les deux cas, le résultat sera

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
2
jihor

Voici une façon plus MATLAB'esque de trouver les combinaisons. Celui-ci peut également être facilement étendu à plus de 2 vecteurs (et aussi à des combinaisons non numériques):

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)]'
1
pAtrick

À partir de la version R2015a, vous pouvez le faire en utilisant repelem et 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

Ce type de solution évite les variables intermédiaires supplémentaires requises par certaines des autres solutions (telles que celles basées sur meshgrid ), ce qui pourrait entraîner des problèmes de mémoire pour des vecteurs plus grands.

1
gnovice

Ce que vous cherchez, c'est le produit cartésien

cartprod est la fonction qui l'implémente. Vous pouvez le trouver dans le package d'algèbre linéaire, vous devez donc faire:

   >> 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    
0
elviejo79