Des clés en double dans les dictionnaires .NET?

Existe-t-il des classes de dictionnaire dans la bibliothèque de classes de base .NET permettant l’utilisation de clés en double? La seule solution que j’ai trouvée consiste à créer, par exemple, une classe comme:

Dictionary<string, List> 

Mais c’est très irritant à utiliser. En Java, je crois qu’un MultiMap accomplit cela, mais ne peut pas trouver d’analogue dans .NET.

    Si vous utilisez .NET 3.5, utilisez la classe Lookup .

    EDIT: vous créez généralement une Lookup utilisant Enumerable.ToLookup . Cela suppose que vous n’avez pas besoin de le changer par la suite, mais je trouve généralement que cela suffit.

    Si cela ne fonctionne pas pour vous, je ne pense pas qu’il y ait quoi que ce soit dans le cadre qui puisse vous aider – et l’utilisation du dictionnaire est aussi bonne que possible 🙁

    La classe List fonctionne en fait assez bien pour les collections clé / valeur contenant des doublons où vous souhaitez effectuer une itération sur la collection. Exemple:

     List> list = new List>(); // add some values to the collection here for (int i = 0; i < list.Count; i++) { Print(list[i].Key, list[i].Value); } 

    Voici une façon de le faire avec List >

     public class ListWithDuplicates : List> { public void Add(ssortingng key, ssortingng value) { var element = new KeyValuePair(key, value); this.Add(element); } } var list = new ListWithDuplicates(); list.Add("k1", "v1"); list.Add("k1", "v2"); list.Add("k1", "v3"); foreach(var item in list) { ssortingng x = ssortingng.format("{0}={1}, ", item.Key, item.Value); } 

    Sorties k1 = v1, k1 = v2, k1 = v3

    Si vous utilisez des chaînes à la fois comme clés et valeurs, vous pouvez utiliser System.Collections.Specialized.NameValueCollection , qui renverra un tableau de valeurs de chaîne via la méthode GetValues ​​(ssortingng key).

    Je viens de trouver la bibliothèque PowerCollections qui comprend, entre autres, une classe appelée MultiDictionary. Cela enveloppe parfaitement ce type de fonctionnalité.

    Note très importante concernant l’utilisation de Lookup:

    Vous pouvez créer une instance de Lookup(TKey, TElement) en appelant ToLookup sur un object qui implémente IEnumerable(T)

    Il n’y a pas de constructeur public pour créer une nouvelle instance de Lookup(TKey, TElement) . De plus, les objects Lookup(TKey, TElement) sont immuables, c’est-à-dire que vous ne pouvez pas append ou supprimer des éléments ou des clés d’un object Lookup(TKey, TElement) après sa création.

    (à partir de MSDN)

    Je pense que ce serait un arrêt de spectacle pour la plupart des utilisations.

    Je pense que quelque chose comme List> ferait le Job.

    Si vous utilisez> = .NET 4, vous pouvez utiliser la classe Tuple :

     // declaration var list = new List>>(); // to add an item to the list var item = Tuple>("key", new List); list.Add(item); // to iterate foreach(var i in list) { Console.WriteLine(i.Item1.ToSsortingng()); } 

    Jetez un coup d’œil à la classe HashBag de C5 .

    En réponse à la question initiale. Quelque chose comme Dictionary> est implémenté dans une classe appelée MultiMap dans The Code Project .

    Vous pouvez trouver plus d’informations sur le lien ci-dessous: http://www.codeproject.com/KB/cs/MultiKeyDictionary.aspx

    Il est assez facile de “lancer votre propre version” d’un dictionnaire qui permet les entrées “dupliquer la clé”. Voici une implémentation simple et approximative. Vous voudrez peut-être envisager d’append le support pour l’essentiel (sinon tous) sur IDictionary .

     public class MultiMap { private readonly Dictionary> storage; public MultiMap() { storage = new Dictionary>(); } public void Add(TKey key, TValue value) { if (!storage.ContainsKey(key)) storage.Add(key, new List()); storage[key].Add(value); } public IEnumerable Keys { get { return storage.Keys; } } public bool ContainsKey(TKey key) { return storage.ContainsKey(key); } public IList this[TKey key] { get { if (!storage.ContainsKey(key)) throw new KeyNotFoundException( ssortingng.Format( "The given key {0} was not found in the collection.", key)); return storage[key]; } } } 

    Un exemple rapide sur la façon de l’utiliser:

     const ssortingng key = "supported_encodings"; var map = new MultiMap(); map.Add(key, Encoding.ASCII); map.Add(key, Encoding.UTF8); map.Add(key, Encoding.Unicode); foreach (var existingKey in map.Keys) { var values = map[existingKey]; Console.WriteLine(ssortingng.Join(",", values)); } 

    NameValueCollection prend en charge plusieurs valeurs de chaîne sous une clé (qui est également une chaîne), mais c’est le seul exemple que je connaisse.

    J’ai tendance à créer des constructions similaires à celle de votre exemple lorsque je rencontre des situations où j’ai besoin de ce type de fonctionnalité.

    Lorsque vous utilisez l’ List> , vous pouvez utiliser LINQ pour effectuer la recherche:

     List> myList = new List>(); //fill it here var q = from a in myList Where a.Key.Equals("somevalue") Select a.Value if(q.Count() > 0){ //you've got your value } 

    Voulez-vous dire congru et pas un doublon réel? Sinon, une hashtable ne pourrait pas fonctionner.

    Congruent signifie que deux clés distinctes peuvent hacher à la valeur équivalente, mais les clés ne sont pas égales.

    Par exemple: disons que la fonction de hachage de votre hashtable était juste hashval = clé mod 3. Les deux 1 et 4 correspondent à 1, mais sont des valeurs différentes. C’est là que votre idée de liste entre en jeu.

    Lorsque vous devez rechercher 1, cette valeur est hachée à 1, la liste est parcourue jusqu’à ce que la clé = 1 soit trouvée.

    Si vous avez autorisé l’insertion de clés en double, vous ne pourrez pas différencier les clés correspondant à quelles valeurs.

    Je suis tombé sur cet article à la recherche de la même réponse, et je n’en ai trouvé aucune, alors j’ai créé une solution de base en utilisant une liste de dictionnaires, remplaçant l’opérateur [] pour append un nouveau dictionnaire à la liste clé donnée (ensemble), et renvoyer une liste de valeurs (get).
    C’est moche et inefficace, il ne récupère / définit que par clé, et il retourne toujours une liste, mais ça marche:

      class DKD { List> dictionaries; public DKD(){ dictionaries = new List>();} public object this[ssortingng key]{ get{ ssortingng temp; List valueList = new List(); for (int i = 0; i < dictionaries.Count; i++){ dictionaries[i].TryGetValue(key, out temp); if (temp == key){ valueList.Add(temp);}} return valueList;} set{ for (int i = 0; i < dictionaries.Count; i++){ if (dictionaries[i].ContainsKey(key)){ continue;} else{ dictionaries[i].Add(key,(string) value); return;}} dictionaries.Add(new Dictionary()); dictionaries.Last()[key] =(ssortingng)value; } } } 

    La façon dont j’utilise est juste un

    Dictionary>

    De cette façon, vous avez une seule clé contenant une liste de chaînes.

    Exemple:

     List value = new List(); if (dictionary.Contains(key)) { value = dictionary[key]; } value.Add(newValue); 

    J’ai modifié la réponse de @Hector Correa en une extension avec des types génériques et j’ai également ajouté un TryGetValue personnalisé.

      public static class ListWithDuplicateExtensions { public static void Add(this List> collection, TKey key, TValue value) { var element = new KeyValuePair(key, value); collection.Add(element); } public static int TryGetValue(this List> collection, TKey key, out IEnumerable values) { values = collection.Where(pair => pair.Key.Equals(key)).Select(pair => pair.Value); return values.Count(); } } 

    Ceci est un chemin de remorquage Dictionnaire simultané Je pense que cela vous aidera:

     public class HashMapDictionary : System.Collections.IEnumerable { private System.Collections.Concurrent.ConcurrentDictionary> _keyValue = new System.Collections.Concurrent.ConcurrentDictionary>(); private System.Collections.Concurrent.ConcurrentDictionary> _valueKey = new System.Collections.Concurrent.ConcurrentDictionary>(); public ICollection Keys { get { return _keyValue.Keys; } } public ICollection Values { get { return _valueKey.Keys; } } public int Count { get { return _keyValue.Count; } } public bool IsReadOnly { get { return false; } } public List this[T1 index] { get { return _keyValue[index]; } set { _keyValue[index] = value; } } public List this[T2 index] { get { return _valueKey[index]; } set { _valueKey[index] = value; } } public void Add(T1 key, T2 value) { lock (this) { if (!_keyValue.TryGetValue(key, out List result)) _keyValue.TryAdd(key, new List() { value }); else if (!result.Contains(value)) result.Add(value); if (!_valueKey.TryGetValue(value, out List result2)) _valueKey.TryAdd(value, new List() { key }); else if (!result2.Contains(key)) result2.Add(key); } } public bool TryGetValues(T1 key, out List value) { return _keyValue.TryGetValue(key, out value); } public bool TryGetKeys(T2 value, out List key) { return _valueKey.TryGetValue(value, out key); } public bool ContainsKey(T1 key) { return _keyValue.ContainsKey(key); } public bool ContainsValue(T2 value) { return _valueKey.ContainsKey(value); } public void Remove(T1 key) { lock (this) { if (_keyValue.TryRemove(key, out List values)) { foreach (var item in values) { var remove2 = _valueKey.TryRemove(item, out List keys); } } } } public void Remove(T2 value) { lock (this) { if (_valueKey.TryRemove(value, out List keys)) { foreach (var item in keys) { var remove2 = _keyValue.TryRemove(item, out List values); } } } } public void Clear() { _keyValue.Clear(); _valueKey.Clear(); } IEnumerator IEnumerable.GetEnumerator() { return _keyValue.GetEnumerator(); } } 

    exemples:

     public class TestA { public int MyProperty { get; set; } } public class TestB { public int MyProperty { get; set; } } HashMapDictionary hashMapDictionary = new HashMapDictionary(); var a = new TestA() { MyProperty = 9999 }; var b = new TestB() { MyProperty = 60 }; var b2 = new TestB() { MyProperty = 5 }; hashMapDictionary.Add(a, b); hashMapDictionary.Add(a, b2); hashMapDictionary.TryGetValues(a, out List result); foreach (var item in result) { //do something } 

    U peut définir une méthode pour construire une clé de chaîne Compound chaque fois que vous voulez utiliser le dictionnaire. Vous devez utiliser cette méthode pour créer votre clé, par exemple:

     private ssortingng keyBuilder(int key1, int key2) { return ssortingng.Format("{0}/{1}", key1, key2); } 

    pour l’utilisation:

     myDict.ContainsKey(keyBuilder(key1, key2)) 

    Les clés en double rompent l’intégralité du contrat du dictionnaire. Dans un dictionnaire, chaque clé est unique et associée à une valeur unique. Si vous voulez lier un object à un nombre arbitraire d’objects supplémentaires, le meilleur pari peut être quelque chose qui ressemble à un DataSet (dans le langage courant, un tableau). Mettez vos clés dans une colonne et vos valeurs dans l’autre. C’est beaucoup plus lent qu’un dictionnaire, mais c’est votre compromis pour perdre la possibilité de hacher les objects clés.

    C’est aussi possible:

     Dictionary previousAnswers = null; 

    De cette façon, nous pouvons avoir des clés uniques. J’espère que cela fonctionne pour toi.

    Vous pouvez append les mêmes clés avec des cas différents comme:

    clé1
    Key1
    Clé1
    KeY1
    kEy1
    keY1

    Je sais que c’est la réponse factice, mais a travaillé pour moi.