Copier des éléments dans un autre vecteur

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut,

J'essaye de coder un programme simple avec deux entrée et des sorties. Entrées: un entier A et un vecteur ligne B. Sorties: Deux vecteurs C et D. Dans C, on met tous les éléments de B > A/2 et dans D tous les éléments de B < 2A.

J'ai fais ça comme ça mais ça ne compile pas quand j'appelle la fonction ça ne me donne pas le résultat voulu. Dans D par exemple il me met que 1 comme valeur et il m'imprime plein de fois C (de façon incorrecte).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
function [C, D] = ArraySorting(A, B)
[d1, d2] = size(B);
for i = 1:d2
    if(B(1,i)> A/2)

        C(1,i) = B(1,i)

    elseif(B(1,i) < 2*A)

        D(1,i) = B(1,i)
    end

end
'C'
disp(C)
'D'
disp(D)
end

J'ai écris ce programme d'une façon similaire avec de la programmation (en utilisant des pointeurs) et ça marche.

Merci.

Édité par sotibio

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Salut,

Alors il y a beaucoup à dire sur ton code. Je vais m'y prendre ligne par ligne.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function [C, D] = ArraySorting(A, B)

[d1, d2] = size(B);
% Tu ne te sers pas de d1, tu pourrais remplacer cette ligne par :
% [~, d2] = size(B);
% Le symbole ~ sert à dire qu'on ne va pas utiliser le résultat.
% Comme B est un vecteur, il y a en vérité encore mieux :
% d2 = length(B)

% Évite de mettre trop de sauts de ligne, cela nuit un peu à la lisibilité.
% Ta boucle est une solution qui peut fonctionner, mais tu fais des erreurs de raisonnement.
% Je rajoute les lignes suivantes, j'explique pourquoi après.
i_c = 1
i_d = 1
for i = 1:d2
    % B n'a qu'une dimension (vecteur), tu peux remplacer par
    % if (B(i) > A/2)
    % Pareil pour le reste.
    if(B(1,i)> A/2)
        C(1,i_c) = B(i)
        % Ici, tu risques de "sauter" des cases dans C... 
        % qui vont être remplies par la valeur par défaut
        % tu dois maintenir un compteur d'avancement pour C :
        i_c = i_c + 1
    % Attention, ici tu fais un elseif alors que tu veux faire un "if"... 
    % Tu vas louper des élements  sinon.
    elseif(B(1,i) < 2*A)
        D(1,i_d) = B(1,i)
        % idem que pour C :
        i_d = i_d + 1
    end
end

Alors j'ai mis beaucoup de commentaires pour améliorer ton code, mais il faut savoir que ton code est maladroit en Matlab (en plus d'être probablement très lent). Une solution plus canonique est la suivante.

1
2
3
function [C, D] = ArraySorting(A, B)
C = B(B(:) > A/2)
D = B(B(:) < 2*A)

Voilà une version commentée (et décomposée) pour te faciliter sa compréhension.

1
2
3
4
5
6
7
8
function [C, D] = ArraySorting(A, B)
% Vecteur de la taille de B, avec est_superieur(i) = 1 si B(i) > A/2 et 0 sinon.
est_superieur = B(:) > A/2
% Technique de filtrage : B(est_superieur) renvoie les élements de B pour lequel est_superieur vaut 1,
% et laisse de côté les autres.
C = B(est_superieur) % C contient donc ici les élements de B > A/2
% Idem que pour C.
D = B(B(:) < 2*A)

Avertissement. Les codes n'ont pas été testé avec Matlab, mais Scilab, une alternative plus ou moins compatible.

+1 -0

Cette réponse a aidé l'auteur du sujet

Je confirme à mon VDD que ca marche avec Matlab/Octave aussi :)

Ce qu'il faut bien garder en tête en Matlab, c'est que tout est des vecteurs. Du coup les codes sont normalement "simple" à vectoriser. La plupart des boucles est souvent évitable.

Les vecteurs sont très facilement manipulables. Par exemple si tu as un vecteur/matrice B qui possède un ensemble de valeur et que tu veux extraire celle qui sont supérieures à A, l'opération

1
index = B>A

retourne un vecteur logique avec 0 quand B est inférieur à A, et 1 quand B est supérieur à A. Du coup, tu peux extraire les valeurs de B supérieures à A grâce à l'indexation logique, c'est-à-dire utiliser le vecteur index

1
B_superieur_a_A = B(index)

C'est exactement ce que mon VDD a fait :)

À noter que B soit un vecteur ou une matrice, ca marchera. Les matrices sont en effet stockées sous forme de grand vecteur. Exemple :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
>> A=rand(5) % On crée la matrice
A =

   0.7707358   0.9795850   0.1195359   0.0952663   0.7305514
   0.4118413   0.8146080   0.7029609   0.6047948   0.8064194
   0.6544155   0.1868782   0.8903577   0.7260080   0.8458382
   0.0029963   0.1469977   0.8247714   0.0304943   0.7623086
   0.7716072   0.1342229   0.1388872   0.2590260   0.4139388
>>> A>0.5 % On crée un vecteur logique pour les valeurs de A supérieures à 0.5
ans =

   1   1   0   0   1
   0   1   1   1   1
   1   0   1   1   1
   0   0   1   0   1
   1   0   0   0   0
>>> A(ans) % On extrait les valeurs de A grâce au vecteur logique.
ans =

   0.77074
   0.65442
   0.77161
   0.97958
   0.81461
   0.70296
   0.89036
   0.82477
   0.60479
   0.72601
   0.73055
   0.80642
   0.84584
   0.76231

Attention petit exercice maintenant (juste pour le fun) :D !

J'ai 2 matrices taille et poids, est-ce que tu peux extraire la taille des personnes qui font plus de 65 kg ?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
>> poids=60+rand(5)*10 % poids en kg
poids =

   62.081   62.836   69.842   69.180   64.492
   65.649   68.200   62.832   69.286   62.689
   69.446   65.954   68.616   68.964   61.011
   67.353   64.217   68.003   67.550   63.983
   65.850   64.565   66.210   65.789   67.265

>> taille=160+rand(5)*10 % taille en cm
taille =

   162.73   167.90   163.95   162.78   160.36
   162.16   163.54   166.51   169.08   167.17
   162.82   165.82   166.53   161.53   168.30
   164.80   162.06   161.87   167.95   164.84
   160.32   168.39   163.49   163.55   165.35

Et sa solution :

Première solution :

1
resultat=taille(poids>65)

Deuxième solution, un peu plus détaillée :

1
2
idx=poids>65;
resultat=taille(idx)

Avec une boucle ca marcherait aussi… Mais ca serait beaaaaaaaucoup plus lourd à écrire, et pour de grande matrice le code serait beaaaaaaaucoup plus long :)

Édité par Gwend@l

+1 -0
Auteur du sujet

Merci beaucoup ! Comment connaissez-vous toutes ces fonctions en fait ? C'est surtout avec l'habitude je suppose ? Est-il important pour des programmes (petits) comme ça de les optimiser ?

Gwend@l: J'ai fais ton exercice et j'ai eu "bon" mais avec des boucles malheureusement donc pas optimal :(

+1 -0
Staff

Salut,

Pour connaître toutes ces fonctions, il n'y a pas grand chose d'autre que la pratique (lire le code des autres, se renseigner sur la meilleure manière de faire, etc.).

Pour un petit programme, l'optimisation n'est pas très importante. Cependant, il faut savoir que les solutions sans boucle peuvent être plus de 10 fois plus rapides. Je te conseille ce document au sujet des optimisations.

Édité par Aabu

+0 -0

En dehors des questions d'optimisations, qui en effet ne sont pas importante pour des petits programmes, c'est surtout une question de "philosophie" du langage de programmation. Matlab (et GNU Octave/Scilab) est fait pour vectoriser un maximum le code. Il a été créé pour faire du calcul matriciel, du coup toutes ses fonctions sont orientées dans ce sens.

Par exemple, tu cherche l'emplacement de la valeur x dans un vecteur vec, plutôt que de faire une boucle sur tous les éléments de vec et utilisé des conditions du style

1
2
3
4
5
for i=1:length(vec)
  if vec(i)==x
    disp(i)
  end
end

qui marche mais qui est lourd et pas très compréhensible du premier coup d'oeil, tu fais un

1
find(vec == x)

Au final ca te simplifie le code :) Et tu t'y repères mieux.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte