// ========================================================================
//
// Copyright (C) 2016-2017 MARC CHEVALDONNE
//                         marc.chevaldonne.free.fr
//
// Module        : Program.cs
// Author        : Marc Chevaldonné
// Creation date : 2016-09-29
//
// ========================================================================

using static System.Console;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Collections;

namespace ex_023_014_Dictionary
{
    /// <summary>
    /// le dictionnaire est la collection la plus utilisée en .NET avec la List
    /// Il utilise une structure de données en hashtable (d'ailleurs la version non générique du dictionnaire est HashTable).
    /// Il stocke des pairs clé-valeur.
    /// Il est rapide et efficace.
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            OutputEncoding = Encoding.Unicode;
 
            //déclaration d'un dictionnaire
            var dico = new Dictionary<string, int>();

            //on peut aussi déclarer le dictionnaire avec des valeurs directement :
            dico = new Dictionary<string, int>
            {
                {"Michael", 1 },
                {"Dwight", 0 },
                {"Angela", 1},
                {"Pam", 2 }
            };

            //et depuis C#6, on peut également initialiser le dictionnaire avec des valeurs avec la notation suivante :
            dico = new Dictionary<string, int>
            {
                ["Michael"] = 1,
                ["Dwight"] = 0,
                ["Angela"] = 1,
                ["Pam"] = 2
            };

            dico = new Dictionary<string, int>();

            //pour ajouter des paires clé-valeur, on peut utiliser la méthode Add, ou bien l'indexeur TValue this[TKey]
            dico.Add("Romain", 1);  //ajoute un nouveau couple "Romain", 1
            dico["Simon"] = 2;      //ajoute un nouveau couple "Simon", 2
            dico["Guillaume"] = 2;  //ajoute un nouveau couple "Guillaume", 2

            //si la paire clé-valeur existe déjà, l'indexeur permet de modifier la valeur
            dico["Guillaume"] = 3;  //modifie la valeur du couple dont la clé est "Guillaume" en 3

            //l'indexeur est utilisable en écriture et en lecture
            dico["Romain"]++;       //modifie la valeur du couple dont la clé est "Romain" en 2

            WriteLine($"valeur de 'Romain' : {dico["Romain"]}");
            WriteLine($"valeur de 'Simon' : {dico["Simon"]}");
            WriteLine($"valeur de 'Guillaume' : {dico["Guillaume"]}");

            //les méthodes ContainsKey et ContainsValue permettent de rechercher une clé en particulier ou une valeur en particulier
            WriteLine($"le dico contient-il une clé 'Simon' ? {dico.ContainsKey("Simon")}");
            WriteLine($"le dico contient-il une valeur '2' ? {dico.ContainsValue(2)}");

            //TryGetValue : sert à tester si la clé existe, et si c'est le cas, rend la valeur associée dans le paramètre out
            int val;
            if (!dico.TryGetValue("Simon", out val))
            {
                WriteLine("pas de Simon");
            }
            else
            {
                WriteLine($"Simon existe {val} fois");
            }

            if (!dico.TryGetValue("Gertrude", out val))
            {
                WriteLine("pas de Gertrude");
            }
            else
            {
                WriteLine("Gertrude existe");
            }

            //enumeration
            //même si cela ne cherche pas à grand chose, on peut énumérer toutes les paires clé-valeur d'un dictionnaire avec foreach
            // chaque élément est de type KeyValuePair<TKey, TValue>
            WriteLine("***********************");
            foreach (KeyValuePair<string, int> pair in dico)
            {
                WriteLine($"{pair.Key}   {pair.Value}");
            }
            WriteLine("***********************");

            //Keys permet d'obtenir toutes les clés en une collection
            foreach (string s in dico.Keys)
            {
                WriteLine(s);
            }
            WriteLine("***********************");

            //Values permet d'obtenir toutes les valeurs en une collection 
            foreach (int i in dico.Values)
            {
                WriteLine(i);
            }



            // il existe plusieurs dictionnaires en C# :
            // - ListDictionary : non générique, utilise en interne une liste simplement chaînée.
            //   son seul intérêt est pour l'utilisation de dictionnaires avec une dizaine de paires clé-valeur uniquement.
            // - OrderedDictionary : non générique, NON trié. Il conserve l'ordre d'insertion et permet d'accéder aux éléments par indice.
            // - SortedDictionary<TKey, TValue> : générique, utilise un red/black tree. Trie les paires en comparant les clés lors de l'insertion.
            // - SortedList<TKey, TValue> : générique, utilise un double tableau. Trie les paires clé-valeur en comparant les clés lors de l'insertion et permet d'accéder aux éléments par indice
            WriteLine("Insertion de [\"mille\", 1000], [\"dix\", 10] et [\"cent\", 100] dans un Dictionary<string, int>");
            Dictionary<string, int> d = new Dictionary<string, int>();
            d.Add("mille", 1000);
            d.Add("dix", 10);
            d.Add("cent", 100);
            foreach (KeyValuePair<string, int> pair in d)
            {
                WriteLine($"{pair.Key} - {pair.Value}");
            }
            WriteLine("***********************\n");

            WriteLine("Insertion de [1000, \"mille\"], [10, \"dix\"] et [100, \"cent\"] dans un SortedDictionary<int, string>");
            SortedDictionary<int, string> sd = new SortedDictionary<int, string>();
            sd.Add(1000, "mille");
            sd.Add(10, "dix");
            sd.Add(100, "cent");
            foreach (KeyValuePair<int, string> pair in sd)
            {
                WriteLine($"{pair.Key} - {pair.Value}");
            }
            WriteLine("***********************\n");

            WriteLine("Insertion de [1000, \"mille\"], [10, \"dix\"] et [100, \"cent\"] dans un SortedList<int, string>");
            SortedList<int, string> sl = new SortedList<int, string>();
            sl.Add(1000, "mille");
            sl.Add(10, "dix");
            sl.Add(100, "cent");
            foreach (KeyValuePair<int, string> pair in sl)
            {
                WriteLine($"{pair.Key} - {pair.Value}");
            }
            WriteLine("***********************\n");

            WriteLine("Insertion de [1000, \"mille\"], [10, \"dix\"] et [100, \"cent\"] dans un OrderedDictionary");
            OrderedDictionary od = new OrderedDictionary();
            od.Add(1000, "mille");
            od.Add(10, "dix");
            od.Add(100, "cent");
            foreach (DictionaryEntry pair in od)
            {
                WriteLine($"{pair.Key} - {pair.Value}");
            }
        }
    }
}
