c# .net dictionary insert-update

c# dictionary



Diccionario.NET: obtener o crear nuevo (4)

¿Y qué hay de esto?

var keyValues = dictionary[key] = dictionary.ContainsKey(key) ? dictionary[key] : new List<string>(); keyValues.Add(aValueForKey);

A menudo me encuentro creando un Dictionary con una clase de valor no trivial (por ejemplo, List ) y luego siempre escribo el mismo patrón de código al completar los datos.

Por ejemplo:

var dict = new Dictionary<string, List<string>>(); string key = "foo"; string aValueForKey = "bar";

Es decir, quiero insertar "bar" en la lista que corresponde a la tecla "foo" , donde la tecla "foo" podría no estar asignada a nada.

Aquí es donde uso el patrón que siempre se repite:

List<string> keyValues; if (!dict.TryGetValue(key, out keyValues)) dict.Add(key, keyValues = new List<string>()); keyValues.Add(aValueForKey);

¿Hay una forma más elegante de hacer esto?

Preguntas relacionadas que no tienen respuestas a esta pregunta:

  • ¿Hay una implementación de IDictionary que devuelve nulo en la clave faltante en lugar de lanzar?
  • Buscar o insertar con una sola búsqueda en c # dictionary
  • Diccionario que devuelve un valor predeterminado si la clave no existe

Al igual que con tantos problemas de programación, cuando te encuentras haciendo mucho, refáctalo con un método:

public static void MyAdd<TKey, TCollection, TValue>( this Dictionary<TKey, TCollection> dictionary, TKey key, TValue value) where TCollection : ICollection<TValue>, new() { TCollection collection; if (!dictionary.TryGetValue(key, out collection)) { collection = new TCollection(); dictionary.Add(key, collection); } collection.Add(value); }


Ok, enfoque diferente:

public static bool TryAddValue<TKey,TValue>(this System.Collections.Generic.IDictionary<TKey,List<TValue>> dictionary, TKey key, TValue value) { // Null check (useful or not, depending on your null checking approach) if (value == null) return false; List<TValue> tempValue = default(List<TValue>); try { if (!dictionary.TryGetValue(key, out tempValue)) { dictionary.Add(key, tempValue = new List<TValue>()); } else { // Double null check (useful or not, depending on your null checking approach) if (tempValue == null) { dictionary[key] = (tempValue = new List<TValue>()); } } tempValue.Add(value); return true; } catch { return false; } }

De esta manera, tiene que "intentar agregar" su valor a una Lista genérica (obviamente generalizable a una colección genérica), comprobar nulo e intentar obtener claves / valores existentes en su Diccionario. Uso y ejemplo:

var x = new Dictionary<string,List<string>>(); x.TryAddValue("test", null); // return false due to null value. Doesn''t add the key x.TryAddValue("test", "ok"); // it works adding the key/value x.TryAddValue("test", "ok again"); // it works adding the value to the existing list

Espero eso ayude.


Tenemos una versión ligeramente diferente de esto, pero el efecto es similar:

public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) where TValue : new() { TValue val; if (!dict.TryGetValue(key, out val)) { val = new TValue(); dict.Add(key, val); } return val; }

Llamado:

var dictionary = new Dictionary<string, List<int>>(); List<int> numbers = dictionary.GetOrCreate("key");

Hace uso de la restricción genérica para constructores públicos sin parámetros: where TValue : new() .

Para ayudar con el descubrimiento, a menos que el método de extensión sea bastante específico para un problema limitado, tendemos a colocar los métodos de extensión en el espacio de nombres del tipo que están extendiendo, en este caso:

namespace System.Collections.Generic

La mayoría de las veces, la persona que usa el tipo tiene la instrucción de using definida en la parte superior, por lo que IntelliSense también encontrará los métodos de extensión definidos en su código.