Affichage des articles dont le libellé est C#. Afficher tous les articles
Affichage des articles dont le libellé est C#. Afficher tous les articles

vendredi 14 août 2009

L’instruction yield pour récupérer la sélection d’éléments d’une liste

L'idée n'est pas de faire un cours sur l'instruction yield, pour cela voir les liens suivants :

http://msdn.microsoft.com/fr-fr/library/9k7k7cf0.aspx

http://romainverdier.developpez.com/articles/dotnet/le-mot-cle-yield-et-les-iterateurs-en-csharp/

Mais de donner un petit plus quand on code avec des listes et très souvent on refait la même chose à savoir récupérer la sélection d'une liste pour lui appliquer un traitement particulier.

Donc le but du jeu est ; Comment peut-on faire pour éviter la duplication des Foreach ou While ou autre afin de récupérer une sélection d’éléments ?
Pour être le plus souple possible, je propose d’utiliser une méthode, nommé Cast, qui soit le plus générique possible.

        // Méthode qui permet d'extraire les objets d'une collection.
        // Valable à partir de Framework .NET 2.0
        // On peut mettre cette méthode dans une classe d’aide(Helper)
        // de facon à l'appeler ailleur pour tout objet qui contient
        // une collection IEnumerable (listBox,)
        IEnumerable<T> Cast<T>(IEnumerable items)
        {
            foreach (object item in items)
                yield return (T)item;
        }

Dans l’exemple suivant, j’utilise une class nommé Personne comme type avec deux propriétés, à savoir : Nom et Prenom. L’utilisation d’un objet string ou autre est possible aussi (voir l’exemple dans le code complet).
Voila le code dans sa totalité.

Merci Éric pour tes idées :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Collections;
using System.Windows.Forms;

namespace Yield_SelectedItems
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();

            List<Personne> personnes = new List<Personne>();
            personnes.Add(new Personne("Hugo", "Victor"));
            personnes.Add(new Personne("Zola", "Emile"));
            personnes.Add(new Personne("Dupont", "Thomas"));
            personnes.Add(new Personne("Dupond", "Daniel"));
            personnes.Add(new Personne("Super Dupond", "Daniel"));

            listBox1.Items.Clear();
            listBox1.Items.AddRange(personnes.ToArray());

        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Récupérer que les objets sélectionnés
            List<Personne> maSelections = new List<Personne>(Cast<Personne>(listBox1.SelectedItems));

            // On créer un objet list de type (chaine de caractère) pour générer
            // avec la méthode Join un saut de ligne facilement, sans avoir à 
            // gérer le premier ou le dernier retour chariot de trop.
            List<string> s = new List<string>();
            foreach (Personne onePersonne in maSelections)
            {
                s.Add(string.Format("{0} {1}", onePersonne.Prenom, onePersonne.Nom));
            }
            String nomPrenom = string.Join("\r", s.ToArray());

            // On affiche le résultat.
            System.Windows.Forms.MessageBox.Show(nomPrenom);


            // Démo avec une list de string
            ListBox mesProduits = new ListBox();
            mesProduits.SelectionMode = SelectionMode.MultiExtended;
            mesProduits.Items.Clear();

            // J'alimente ma listbox
            List<string> listProduits = new List<string>();
            listProduits.Add("Produit A");
            listProduits.Add("Produit B");
            listProduits.Add("Produit C");
            listProduits.Add("Produit D");
            listProduits.Add("Produit E");
            mesProduits.Items.Clear();
            mesProduits.Items.AddRange(listProduits.ToArray());

            // Je sinule une sélection
            mesProduits.SelectedItems.Add(listProduits[0]);
            mesProduits.SelectedItems.Add(listProduits[3]);

            // On récupère les produits sélectionnés
            List<string> monChoix = new List<string>(Cast<string>(mesProduits.SelectedItems));

            // On les affiches.
            System.Windows.Forms.MessageBox.Show(string.Join("\r", monChoix.ToArray()));


            // Lol, plus simple. Comme quoi des fois...
            Personne[] essai2 = new Personne[listBox1.SelectedItems.Count * 2]; // Je double la taille pour tester le mode Append
            listBox1.SelectedItems.CopyTo(essai2, 0);
            listBox1.SelectedItems.CopyTo(essai2, 3); // Append mode
            List<string> s2 = new List<string>();
            foreach (Personne onePersonne in essai2)
            {
                s2.Add(string.Format("{0} {1}", onePersonne.Prenom, onePersonne.Nom));
            }
            // On les affiches.
            System.Windows.Forms.MessageBox.Show(string.Join("\r", s2.ToArray()));


            // Lol, plus simple. Comme quoi des fois...
            string[] essai3 = new string[mesProduits.SelectedItems.Count];
            mesProduits.SelectedItems.CopyTo(essai3, 0);
            List<string> soluce3 = new List<string>(essai3);
            // On les affiches.
            System.Windows.Forms.MessageBox.Show(string.Join("\r", soluce3.ToArray()));

        }


        // Méthode qui permet d'extraire les objets d'une collection.
        // Valable à partir de Framework .NET 2.0
        // On peut mettre cette méthode dans une classe d’aide(Helper)
        // de facon à l'appeler ailleur pour tout objet qui contient
        // une collection IEnumerable (listBox,)
        IEnumerable<T> Cast<T>(IEnumerable items)
        {
            foreach (object item in items)
                yield return (T)item;
        }

    }


    class Personne
    {
        private string _nom;
        private string _prenom;

        public Personne()
        {
        }

        public Personne(string nom, string prenom)
        {
            Nom = nom;
            Prenom = prenom;
        }

        public string Nom
        {
            get { return _nom; }
            set { _nom = value; }
        }

        public string Prenom
        {
            get { return _prenom; }
            set { _prenom = value; }
        }

        // l'override de la méthode string est utilisé pour populer le listbox.
        public override string ToString()
        {
            return string.Format("{0} {1}", Nom, Prenom);
        }
    }

}

vendredi 17 juillet 2009

Comment trier un objet hashtable sur les valeurs ?

D'accord on est mal parti avec ce titre, car par définition, un objet hashtable n'est pas triable sur les valeurs.

Ce type d'objet est toujours triè sur les clés que l'on insère. À chaque foi que l'on ajoute une entrée, la clé est haché http://fr.wikipedia.org/wiki/Table_de_hachage pour définir sa position dans la table et non pas ajouter l'une derrière l'autre comme dans un tableau ordinaire.

De plus, si on écrit du nouveau code, certainement qu'un objet hashtable n'est pas la bonne manière de faire. Surtout avec les génériques : List<>.

Alors, comment on en arrive là ? En générale, ce cas arrive sur du code existant pour lequel on ne veut pas tout réécrire, à l'origine le besoin était plus simple, question de temps, etc...

Pour les personnes pressées, voici le code de la solution :

using System;
using System.Collections.Generic;
using System.Text;

using System.Collections;

namespace SortHashtable
{
    class Program
    {
        static void Main(string[] args)
        {

            //...
            Hashtable hashtable = new Hashtable();
            hashtable.Add("keyV", 55);
            hashtable.Add("keyG", 99);
            hashtable.Add("keyB", 25);
            hashtable.Add("keyD", 13);
            hashtable.Add("keyL", 77);

            //On affiche les éléments avant le tri.
            System.Console.WriteLine("Avant le tri dans l'objet Hashtable:");
            foreach (DictionaryEntry dicEntry in hashtable)
            {
                System.Console.WriteLine("Key={0} Value={1}", dicEntry.Key, dicEntry.Value);
            }


            IComparer dicEntryComparer = new ComparerDictionnaryEntryOnDoubleValue();

            //On déclare un arraylist.
            ArrayList al = new ArrayList();

            //On ajoute la hashtable dans un arraylist.
            al.AddRange(hashtable);

            //On tri la liste.
            al.Sort(dicEntryComparer);

            //On affiche les éléments de l'arraylist trié.
            System.Console.WriteLine("\nAprès le sort sur les valeurs dans l'objet ArrayList (ordre croissant):");
            foreach (DictionaryEntry dicEntry in al)
            {
                System.Console.WriteLine("Key={0} Value={1}", dicEntry.Key, dicEntry.Value);
            }

            //On fait une pose pour voir le résultat.
            System.Console.ReadKey();

        }
    }

    public class ComparerDictionnaryEntryOnDoubleValue : IComparer
    {
        int IComparer.Compare(object right, object left)
        {
            // Conversion en double des valeurs.
            double l = Convert.ToDouble(((DictionaryEntry)left).Value);
            double r = Convert.ToDouble(((DictionaryEntry)right).Value);

            // On compare l'élément de gauche avec celui de droite.
            // Le boolean qui en résulte informe si l'élément de gauche
            // est plus grand que celui de droite.
            //return (Comparer<double>.Default.Compare(l, r)); // Tri en ordre décroissant.
            return (Comparer<double>.Default.Compare(r, l)); // Tri en ordre croissant.
        }
    }

}
Voici le résutat que vous devez avoir :

Membres