Dizionario multivalore?

Qualcuno sa di una buona implementazione di un MultiValueDictionary ? Fondamentalmente, voglio qualcosa che permetta più valori per chiave. Voglio essere in grado di fare qualcosa del genere

 dict.Add(key, val); 

E se la chiave non esiste già, la aggiungerà, se lo fa, aggiungerà semplicemente un altro valore a quella chiave. Sto solo andando a scorrere su di esso, quindi non mi interessa davvero gli altri metodi di recupero.

Non esiste, ma puoi costruirne uno abbastanza velocemente da Dizionario ed elenco:

 class MultiDict // no (collection) base class { private Dictionary> _data = new Dictionary>(); public void Add(TKey k, TValue v) { // can be a optimized a little with TryGetValue, this is for clarity if (_data.ContainsKey(k)) _data[k].Add(v) else _data.Add(k, new List() { v}) ; } // more members } 

Microsoft ha appena aggiunto una versione ufficiale di prelease di esattamente quello che stai cercando (chiamato MultiDictionary) disponibile attraverso NuGet qui: https://www.nuget.org/packages/Microsoft.Experimental.Collections/

Informazioni sull’utilizzo e ulteriori dettagli sono disponibili sul post ufficiale del blog MSDN qui: http://blogs.msdn.com/b/dotnet/archive/2014/06/20/would-you-like-a-multidictionary.aspx

Sono lo sviluppatore di questo pacchetto, quindi fammi sapere qui o su MSDN se hai domande sulle prestazioni o altro.

Spero possa aiutare.

Puoi facilmente crearne uno da un dizionario di liste:

 public class MultiValueDictionary : Dictionary> { public void Add(Key key, Value value) { List values; if (!this.TryGetValue(key, out values)) { values = new List(); this.Add(key, values); } values.Add(value); } } 

Puoi sempre usare una Tupla per il tuo secondo parametro generico:

 var dict = new Dictionary>(); dict.Add("key", new Tuple("string1", 4, new Object())); 

O anche, un Elenco generico come secondo parametro generico:

 var dict = new Dictionary>(); 

Ciò ti consentirà di associare più valori a una singola chiave.

Per facilità d’uso, è ansible creare un metodo di estensione che verificherà l’esistenza di una chiave e l’aggiunta all’elenco.

Eccone uno che ho scritto qualche tempo fa che puoi usare.

Ha una class “MultiValueDictionary” che eredita dal dizionario.

Ha anche una class di estensione che ti permette di usare la speciale funzionalità Aggiungi su qualsiasi dizionario dove il tipo di valore è un IList; in questo modo non sei obbligato a usare la class personalizzata se non vuoi.

 public class MultiValueDictionary : Dictionary> { ///  /// Hide the regular Dictionary Add method ///  new private void Add(KeyType key, List value) { base.Add(key, value); } ///  /// Adds the specified value to the multi value dictionary. ///  /// The key of the element to add. /// The value of the element to add. The value can be null for reference types. public void Add(KeyType key, ValueType value) { //add the value to the dictionary under the key MultiValueDictionaryExtensions.Add(this, key, value); } } public static class MultiValueDictionaryExtensions { ///  /// Adds the specified value to the multi value dictionary. ///  /// The key of the element to add. /// The value of the element to add. The value can be null for reference types. public static void Add(this Dictionary thisDictionary, KeyType key, ValueType value) where ListType : IList, new() { //if the dictionary doesn't contain the key, make a new list under the key if (!thisDictionary.ContainsKey(key)) { thisDictionary.Add(key, new ListType()); } //add the value to the list at the key index thisDictionary[key].Add(value); } } 

È ansible utilizzare la class MultiDictionary da PowerCollections .

Restituisce ICollection {TValue} per la chiave richiesta.

Solo per aggiungere il mio $ 0,02 alla raccolta di soluzioni:

Ho avuto lo stesso bisogno nel 2011 e MultiDictionary creato un MultiDictionary con MultiDictionary pedanticamente completa di tutte le interfacce .NET. Ciò include gli enumeratori che restituiscono una KeyValuePair standard KeyValuePair e il supporto per la proprietà IDictionary.Values fornisce una raccolta di valori effettivi (invece di una ICollection> ).

In questo modo, si integra perfettamente con il resto delle classi di raccolta .NET. Ho anche definito un’interfaccia IMultiDictionary per accedere alle operazioni che sono particolari per questo tipo di dizionario:

 public interface IMultiDictionary : IDictionary>, IDictionary, ICollection>, IEnumerable>, IEnumerable { /// Adds a value into the dictionary /// Key the value will be stored under /// Value that will be stored under the key void Add(TKey key, TValue value); /// Determines the number of values stored under a key /// Key whose values will be counted /// The number of values stored under the specified key int CountValues(TKey key); ///  /// Removes the item with the specified key and value from the dictionary ///  /// Key of the item that will be removed /// Value of the item that will be removed /// True if the item was found and removed bool Remove(TKey key, TValue value); /// Removes all items of a key from the dictionary /// Key of the items that will be removed /// The number of items that have been removed int RemoveKey(TKey key); } 

Può essere compilato su qualsiasi cosa, da .NET 2.0 verso l’alto e finora l’ho distribuito su Xbox 360, Windows Phone 7, Linux e Unity 3D. C’è anche una suite di test unitaria completa che copre ogni singola riga del codice.

Il codice è concesso in licenza con la Common Public License (breve: tutto va bene, ma correzioni di bug al codice della libreria devono essere pubblicate) e può essere trovato nel mio repository Subversion .

Eppure ecco il mio tentativo di usare ILookup e un KeyedCollection interno. Assicurati che la proprietà della chiave sia immutabile.
Cross pubblicato qui .

 public class Lookup : Collection, ILookup { public Lookup(Func keyForItem) : base((IList)new Collection(keyForItem)) { } new Collection Items => (Collection)base.Items; public IEnumerable this[TKey key] => Items[key]; public bool Contains(TKey key) => Items.Contains(key); IEnumerator> IEnumerable>.GetEnumerator() => Items.GetEnumerator(); class Collection : KeyedCollection { Func KeyForItem { get; } public Collection(Func keyForItem) => KeyForItem = keyForItem; protected override TKey GetKeyForItem(Grouping item) => item.Key; public void Add(TElement item) { var key = KeyForItem(item); if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)) collection.Add(item); else Add(new Grouping(key) { item }); } public bool Remove(TElement item) { var key = KeyForItem(item); if (Dictionary != null && Dictionary.TryGetValue(key, out var collection) && collection.Remove(item)) { if (collection.Count == 0) Remove(key); return true; } return false; } } class Grouping : Collection, IGrouping { public Grouping(TKey key) => Key = key; public TKey Key { get; } } } 

Questo dovrebbe fare per ora …

 public class MultiValueDictionary : IEnumerable> { private Dictionary> _dict = new Dictionary>(); public void Add(TKey key, TValue value) { if(!_dict.ContainsKey(key)) _dict[key] = new LinkedList(); _dict[key].AddLast(value); } public IEnumerator> GetEnumerator() { foreach (var list in _dict) foreach (var value in list.Value) yield return new KeyValuePair(list.Key, value); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } 

Alternativa al tipo personalizzato può essere un’estensione generica che aggiunge chiave e valore quando non trovata:

 public static V getValue(this IDictionary d, K key) where V : new() { V v; if (!d.TryGetValue(key, out v)) { v = new V(); d.Add(key, v); } return v; } 

Uso del campione:

 var d = new Dictionary>(); d.getValue(1).AddLast(2);