2 votes

Comment trouver la position des éléments non nuls dans chaque ligne ?

Étant donné une matrice A est

A=[  0     1     1
     1     0     1]

Comment puis-je trouver l'emplacement des nonzéros dans chaque ligne de la matrice A, sans utiliser de boucle. Le résultat attendu aime

output=[2 3
        1 3]

J'ai été utilisé find mais elle renvoie un résultat inattendu comme

 output=[2
         3
         5
         6]

5voto

Divakar Points 20144

Approche n° 1

Utilisation find pour obtenir les indices des colonnes d'un tableau aplati, puis remodeler -

[c,~] = find(A.')
out = reshape(c,[],size(A,1)).'

Exemple d'exécution -

>> A
A =
     0     1     1
     1     0     1
     1     1     0
>> [c,~] = find(A.');
>> reshape(c,[],size(A,1)).'
ans =
     2     3
     1     3
     1     2

Approche n°2

Nous pourrions éviter la transposition du tableau d'entrée, en effectuant un tri -

[r,c]  = find(A);
[~,idx] = sort(r);
out = reshape(c(idx),[],size(A,1)).'

Analyse comparative

Nous allons regrouper les lignes pour former une matrice d'entrée plus grande et tester les méthodes proposées.

Code d'étalonnage -

% Setup input array
A0 = [ 0 1 1;1 0 1;1,1,0;1,0,1];
N = 10000000; % number of times to tile the input rows to create bigger one
A = A0(randi(size(A0,1),N,1),:);

disp('----------------------------------- App#1')
tic,
[c,~] = find(A.');
out = reshape(c,[],size(A,1)).';
toc
clear c out

disp('----------------------------------- App#2')
tic,
[r,c]  = find(A);
[~,idx] = sort(r);
out = reshape(c(idx),[],size(A,1)).';
toc
clear r c idx out

disp('----------------------------------- Wolfie soln')
tic,
[row, col] = find(A);
[~, idx] = sort(row);
out = [col(idx(1:2:end)), col(idx(2:2:end))];
toc

Horaires -

----------------------------------- App#1
Elapsed time is 0.273673 seconds.
----------------------------------- App#2
Elapsed time is 0.973667 seconds.
----------------------------------- Wolfie soln
Elapsed time is 0.979726 seconds.

Il est difficile de choisir entre App#2 et la solution de @Wolfie car les temps semblent comparables, mais la première semble assez efficace.

2voto

Wolfie Points 16551

Pour ce faire, il suffit de find y sort . J'utiliserai le même exemple de test que la réponse de Divakar pour la continuité.

% Set up some matrix with only 2 non-zero elements per row
A = [ 0     1     1
      1     0     1
      1     1     0 ];

% Find rows/columns of non-zero elements
[row, col] = find(A);
% Get sort indices, should be two of each row value (for two non-zero elems)
[~, idx] = sort(row);
% Concatenate horizontally the first and second column indices from each row
out = [col(idx(1:2:end)), col(idx(2:2:end))];

>> disp(out)
>> [2     3
    1     3
    1     2]

Par rapport à la solution de Divakar, les deux méthodes donnent les mêmes résultats. sort mais cette méthode ne nécessite aucune transposition ou remodelage. Voir aussi cette réponse pour l'étalonnage des performances.

1voto

rahnema1 Points 9765

S'il n'y a que 3 colonnes, vous pouvez utiliser cette méthode :

x = [1 2;1 3;2 3];
output = x((A *(0:2).').',:);

Résultat du benchmark de @Divakar en octave :

----------------------------------- App#1
Elapsed time is 0.813956 seconds.
----------------------------------- App#2
Elapsed time is 0.9617 seconds.
----------------------------------- Wolfie soln
Elapsed time is 1.49294 seconds.
----------------------------------- rahnema1 soln
Elapsed time is 0.221258 seconds.

Nous pouvons la généraliser à d'autres tailles de colonnes :

x=nchoosek(1:size(A,2),2);
output = x((A *(0:size(A,2)-1).').',:);

ou

[a b]=find(tril(true(size(A,2)),-1));
idx = (A *(0:size(A,2)-1).').';
output=[b(idx) a(idx)];

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X