Archives par mot-clé : arrays

l’expression lambda dans le c# : passer à la vitesse supérieure

l’expression lambda en c#: passer à la vitesse supérieure :

vous seriez bien étonnés d’apprendre que nous n’avons fait dans nos précédents article qu’effleurer les différents aspects de l’utilisation de l’expression lambda avec les vecteurs et les tableaux

l’utilisation « normale »  concerne les différents tableaux et vecteurs de type conventionnel bien connu.

Que faire si nous projetons d’utiliser des vecteurs d’un type bien particulier. Un vecteur de classe ou de structure définies par nos soins ?

Deux exemples : le premier  traite d’vecteur de fractions , le deuxième se rapporte à un vecteur de notes musicales dont la structure a été définie par nos soins.

Commençons par le premier exemple en créant ensemble une classe spéciale qui porte le nom de « fraction »

Class fraction  { } ;

Pour que la classe soit visible de partout nous la qualifions de publique.

Public class fraction {} ;

Deux constructeurs sont prévus pour initialiser la classe :

Public fraction (int d) ;

Et

Public fraction (int n, int d) ;

Le premier constructeur présume le numérateur de la fraction égal à 1. L’instruction

New fraction (2) ;

Nous donne donc une fraction d’un demi 1/2..

Le deuxième constructeur plus explicite exige d’indiquer et le numérateur et dénominateur. L’instruction

New fraction (2,4) ;

Nous donne une fraction de deux quarts 2/4 soit toujours la moitié.

Voici tout le code concocté.

public class fraction  

        {

    public int num;

            public int den;

 

          public  fraction (int d)

            {

                this.num = 1;

                this.den = d;

            }

           public fraction (int n, int d)

            {

                this.num = n;

                this.den = d;

            }

         }

Nous proposons ensuite de créer un tableau ou un vecteur de fractions qu’on nommera simplement x.

Fraction x= new fraction [5] ;

Initialisons le tableau avec une suite de fractions

            x[0] = new fraction(1, 10);

            x[1] = new fraction(1, 4);

            x[2] = new fraction(1, 24);

            x[3] = new fraction(1, 10);

            x[4] = new fraction(1, 5);

le défi que nous devons relever est celui d’utiliser l’expression lambda pour traiter des données du vecteur x. trouver par exemple la maximale, la minimale, leurs positions respectives ?

L’instruction crue

fraction max = x.Max();

Entraîne une erreur du compilateur attirant notre attention sur le fait que la classe fraction ne contient aucune méthode CompareTo() qui autoriserait la comparaison entre les différents éléments du vecteur. Méthode nécessaire et suffisante pour trouver la valeur maximale et éventuellement la valeur minimale.

Inutile d’insister. le compilateur tenant bon à sa méthode CompareTo force pour nous d’obtempérer.

Nous reprenons donc notre code écrit pour   la classe « fraction » en déclarant la classe base IComparable.

public class fraction  : IComparable

et en y ajoutant la fameuse méthode CompareTo.

int CompareTo (object obj)

            {

                fraction f = (fraction)obj;

                int n = f.num * den;

                int d = f.den * den;

                int n2 = num * f.den;

                int d2 = den * f.den;

                if(n == n2 )return 0;

                else if (n2 > n) return 1;

                return -1;

    }

La méthode CompareTo commence par calculer le dénominateur commun entre les deux fractions.

Si les deux numérateurs sont égaux notre méthode retourne   zéro pour dire que les deux fractions sont égales si n2 est supérieure à n la méthode retourne 1 sinon elle retourne -1 ;

Notre classe fraction réécrite ressemble maintenant au code suivant :

public class fraction  : IComparable

        {

             public int num;

            public int den;

 

          public  fraction (int d)

            {

                this.num = 1;

                this.den = d;

            }

 

           public fraction (int n, int d)

            {

                this.num = n;

                this.den = d;

            }

       public  int CompareTo (object obj)

            {

                fraction f = (fraction)obj;

                int n = f.num * den;

                int d = f.den * den;

                int n2 = num * f.den;

                int d2 = den * f.den;

                if(n == n2 )return 0;

                else if (n2 > n) return 1;

                 return -1;

  }

}

Désormais nous pouvons sans craindre les foudres du compilateur chercher la plus grande valeur du vecteur x.

Fraction max= x.Max() ;

Ou

fraction max = x.Max(b=> b);

max prend la valeur de 1/4 ;

L’instruction

Fraction min= x.Min() ;

Ou encore

fraction min = x.Min(b=> b);

Nous renvoie 1/24 ;

Pour trier le vecteur de fractions de la plus petite à la plus grande, tri dit ascendant, nous pouvons toujours utiliser l’expression lambda avec l’instruction linq orderby

x = x.OrderBy(b=> b).ToArray ();

le vecteur x est désormais ordonné comme suit

1/24, 1/10 , 1/10 , 1/5, 1/4

L’instruction

x = x.OrderByDescending(b => b).ToArray();

Opère un tri dit descendant.

L’instruction reverse est tout aussi opérationnelle.

x = x.Reverse().ToArray();

  L’instruction indexof déjà rencontrée marche tout aussi bien.

 int pos = x.ToList().IndexOf(max);

 pos = x.ToList().IndexOf(min);

 

 

 

 

 

 

 

(54)

Opérations sur les vecteurs en c# en utilisant l’expression Lambda -2-

Opérations sur les vecteurs en c#  en utilisant l’expression Lambda

Par Ettougourti Mohamed Ali

Nous pouvons aller encore plus loin dans notre exploitation du nouvel outil de programmation que le c# nous offre à savoir l’expression lambda.

(voir article précédent).

L’on peut par exemple ajouter une valeur unique aux différentes valeurs d’un vecteur

x = x.Select(b => b += 0.3).ToArray();

Ou en soustraire une valeur donnée

x = x.Select(b => b -= 0.3).ToArray();

Vous l’avez deviné toutes les opérations arithmétiques sont possibles :

La multiplication:

x = x.Select(b => b *= 0.3).ToArray();

La division:

x = x.Select(b => b /= 0.3).ToArray();

Les précautions d’usage restent de mise pour la division par zéro qui nous donne « infinity » comme résultat.

Les valeurs absolues:

x = x.Select(b => Math.Abs(b)).ToArray();

l’élevation à puissance :

x2 = k2.Select(b => Math.Pow(b, 2)).ToArray();

Pour élever les valeurs de k2, un tableau de type int, à la puissance de 2 nous avons toutefois utilisé un tableau de type double x2 en tant que tableau de destination : Math.pow renvoie en effet une valeur double.

Ces précautions d’usage prises en compte il est possible avec l’expression Lambda d’effectuer toutes les opérations mathématiques sur un vecteur une seule fois et sans recourir à des boucles d’itération.

L’appétit vient en mangeant rien ne peut plus désormais freiner notre élan et l’on est en droit de se demander si d’autres opérations plus fines ne puissent être menées à bien sur des vecteurs.

Le c#  nous offre en matière de tableaux plusieurs instructions de nature à nous faciliter encore plus la tâche.

Ainsi il est possible d’éliminer les doublons d’un vecteur.

Pour ce faire on utilise la fonction ou la méthode « distinct ».

Si l’on initialise un tableau d’entiers avec plusieurs doublons exemple :

int[]k={2,1,2,3,5,3,4,1,6,7,8,2,1,0,8} ;

et si l’on fait appel à distinct() l’on verra qu’une seule valeur des doublons 2,3, 8 ,etc. est retenue et le tableau de rétrécir de 15 éléments à tout juste neuf éléments.

k2 = {2,1,3,5,4,6,7,8,0} ;

Je vois venir votre objection : dans distinct il n’y a pas de signe lambda qui vaille, pourquoi l’invoquer ?

Vous avez raison.  C’est pourquoi je me rattrape sur une autre méthode fort utile qui exige cette fois l’emploi de l’expression lambda.

La méthode sert à trier le tableau par ordre ascendant:

k2 = k2.OrderBy (b=>b).ToArray ();

En inspectant le tableau k2 l’on constate que le zéro initié à la fin du tableau prend désormais la première place et que toutes les valeurs sont bien ordonnées du plus petit au plus grand.

k2 = {0,2,1,3,5,4,6,7,8} ;

Vous ne voulez pas d’un ordre ascendant ?  La même expression lambda nous permet de trier le tableau dans l’ordre descendant du plus grand au plus petit

k2 = k2.OrderByDescending (b => b).ToArray();

Et le tour est joué:

k2 = {8,7,6,5,4,3,2,1,0} ;

Pour faire compliqué alors qu’on peut faire simple on peut évidemment ordonner les valeurs d’un tableau par ordre décroissant ou ascendant puis simplement inverser le tableau grâce à la fonction ou la méthode reverse.

k2.Reverse();

Mais comme vous le constatez l’expression lambda ne figure pas dans l’instruction reverse.

Si vous tenez à employer l’expression lambda dans reverse vous serez vite remis à l’ordre par le compilateur une erreur survient de type « cannot convert lambda expression to type array because it is not a delegate type ».

Ceci n’est pas très clair mais en gros le compilateur refuse d’y aller : ses désirs, comme chacun sait, sont des ordres.

Le plus intéressant reste évidemment de pouvoir travailler sur plusieurs vecteurs.

Pour ce faire nous allons initier un deuxième vecteur baptisé x2 de type double avec des valeurs aléatoire grâce au générateur de nombre aléatoires t précédemment créé.

double[] x2 = new double[100];

x2 = x2.Select(b => b = t.NextDouble()).ToArray();

Pour additionner les valeurs des deux vecteurs nous retrouvons donc notre variable d’itération, next ou index ou de  tout autre nom fantaisiste.(voir article précédent)

Si nous choisissons le vecteur x2 comme vecteur de destination la ligne de code doit s’écrire comme suit :

x2 = x.Select((b,next) => b + x2.ElementAt(next)).ToArray ();

Remarquez que nous pouvons référencer l’élément dans x2 directement à l’aide de deux accolades en reprenant le code sous cette forme:

x2 = x.Select((b, next) => b + x2[next]).ToArray();

C’est aussi avec la même insolite facilité que nous pourrons soustraire un vecteur d’un autre, multiplier deux vecteurs ou diviser l’un par l’autre.

x2 = x.Select((b, next) => b – x2[next]).ToArray();

x2 = x.Select((b, next) => b * x2[next]).ToArray();

x2 = x.Select((b, next) => b / x2[next]).ToArray();

il est tout aussi possible d’effectuer des opérations sur plusieurs tableaux:

x2 = x.Select((b, next) => b + x2[next]* k2[next]).ToArray();

Vous avez testé cette dernière ligne de code et vous avez constaté que ça ne marche pas ?

Autant  pour moi, j’ai oublié de vous parler d’ un détail important:  les tableaux doivent être de même taille d’où l’exception soulevée par le programme : « out of range » ou limites du tableau atteintes.

(164)