c # diccionario una clave muchos valores

Quiero crear un almacén de datos para permitirme almacenar algunos datos.

La primera idea fue crear un diccionario en el que tiene 1 clave con muchos valores, por lo que se parece a una relación de uno a muchos.

Creo que el diccionario solo tiene 1 valor de clave.

¿De qué otra forma podría almacenar esta información?

A partir de .net3.5 + en lugar de usar un Dictionary> puede usar una Lookup del espacio de nombres de Linq:

 // lookup Order by payment status (1:m) // would need something like Dictionary> orderIdByIsPayed ILookup byPayment = orderList.ToLookup(o => o.IsPayed); IEnumerable payedOrders = byPayment[false]; 

Desde msdn :

Una búsqueda se asemeja a un diccionario. La diferencia es que un diccionario asigna claves a valores únicos, mientras que una búsqueda mapea claves para colecciones de valores.

Puede crear una instancia de una búsqueda llamando a ToLookup en un objeto que implementa IEnumerable.

También puede leer esta respuesta a una pregunta relacionada . Para obtener más información, consulte msdn .

Ejemplo completo:

 using System; using System.Collections.Generic; using System.Linq; namespace LinqLookupSpike { class Program { static void Main(String[] args) { // init var orderList = new List(); orderList.Add(new Order(1, 1, 2010, true));//(orderId, customerId, year, isPayed) orderList.Add(new Order(2, 2, 2010, true)); orderList.Add(new Order(3, 1, 2010, true)); orderList.Add(new Order(4, 2, 2011, true)); orderList.Add(new Order(5, 2, 2011, false)); orderList.Add(new Order(6, 1, 2011, true)); orderList.Add(new Order(7, 3, 2012, false)); // lookup Order by its id (1:1, so usual dictionary is ok) Dictionary orders = orderList.ToDictionary(o => o.OrderId, o => o); // lookup Order by customer (1:n) // would need something like Dictionary> orderIdByCustomer ILookup byCustomerId = orderList.ToLookup(o => o.CustomerId); foreach (var customerOrders in byCustomerId) { Console.WriteLine("Customer {0} ordered:", customerOrders.Key); foreach (var order in customerOrders) { Console.WriteLine(" Order {0} is payed: {1}", order.OrderId, order.IsPayed); } } // the same using old fashioned Dictionary Dictionary> orderIdByCustomer; orderIdByCustomer = byCustomerId.ToDictionary(g => g.Key, g => g.ToList()); foreach (var customerOrders in orderIdByCustomer) { Console.WriteLine("Customer {0} ordered:", customerOrders.Key); foreach (var order in customerOrders.Value) { Console.WriteLine(" Order {0} is payed: {1}", order.OrderId, order.IsPayed); } } // lookup Order by payment status (1:m) // would need something like Dictionary> orderIdByIsPayed ILookup byPayment = orderList.ToLookup(o => o.IsPayed); IEnumerable payedOrders = byPayment[false]; foreach (var payedOrder in payedOrders) { Console.WriteLine("Order {0} from Customer {1} is not payed.", payedOrder.OrderId, payedOrder.CustomerId); } } class Order { // key properties public Int32 OrderId { get; private set; } public Int32 CustomerId { get; private set; } public Int32 Year { get; private set; } public Boolean IsPayed { get; private set; } // additional properties // private List _items; public Order(Int32 orderId, Int32 customerId, Int32 year, Boolean isPayed) { OrderId = orderId; CustomerId = customerId; Year = year; IsPayed = isPayed; } } } } 

Observación sobre la inmutabilidad

Por defecto, las búsquedas son inmutables y acceder a las internal implicaría la reflexión. Si necesita mutabilidad y no desea escribir su propio contenedor, podría usar MultiValueDictionary (anteriormente conocido como MultiDictionary ) de corefxlab (anteriormente parte de Microsoft.Experimental.Collections que ya no se actualiza).

Puede usar una lista para el segundo tipo genérico. Por ejemplo, un diccionario de cadenas marcadas por una cadena:

 Dictionary> myDict; 

Microsoft acaba de agregar una versión oficial de prerescripción de exactamente lo que está buscando (llamado MultiDictionary) disponible a través de NuGet aquí: https://www.nuget.org/packages/Microsoft.Experimental.Collections/

Puede encontrar información sobre el uso y más detalles a través de la publicación oficial del blog de MSDN aquí: http://blogs.msdn.com/b/dotnet/archive/2014/06/20/would-you-like-a-multidictionary.aspx

Soy el desarrollador de este paquete, así que avíseme aquí o en MSDN si tiene alguna pregunta sobre el rendimiento o algo.

Espero que ayude.

Actualizar

El MultiValueDictionary ahora está en el repo corefxlab , y usted puede obtener el paquete NuGet de este feed MyGet.

El tipo de valor de su diccionario podría ser una lista u otra clase que contenga varios objetos. Algo como

 Dictionary> 

para un diccionario que está codificado por ints y contiene una lista de cadenas.

Una consideración principal al elegir el tipo de valor es para lo que usará el diccionario, si debe realizar búsquedas u otras operaciones en los valores, entonces tal vez piense en usar una estructura de datos que lo ayude a hacer lo que quiera: – como un HashSet.

Utilizar esta:

 Dictionary> 

Puede usar un Dictionary> .

Eso permitiría que cada tecla haga referencia a una lista de valores.

Use un diccionario de listas (u otro tipo de colección), por ejemplo:

 var myDictionary = new Dictionary>(); myDictionary["My key"] = new List {1, 2, 3, 4, 5}; 

Puede tener un diccionario con una colección (o cualquier otro tipo / clase) como valor. De esta forma, tiene una sola clave y almacena los valores en su colección.

Un diccionario .NET solo tiene una relación de 1 a 1 para claves y valores. Pero eso no significa que un valor no puede ser otra matriz / lista / diccionario.

No puedo pensar en una razón para tener una relación de 1 a muchos en un diccionario, pero obviamente hay una.

Si tiene diferentes tipos de datos que desea almacenar en una clave, entonces eso suena como el momento ideal para crear su propia clase. Entonces tienes un 1 a 1, pero tienes la clase de valor que almacena más de 1 dato.

Eche un vistazo a MultiValueDictionary de Microsoft.

Código de ejemplo:

 MultiValueDictionary Parameters = new MultiValueDictionary(); Parameters.Add("Malik", "Ali"); Parameters.Add("Malik", "Hamza"); Parameters.Add("Malik", "Danish"); //Parameters["Malik"] now contains the values Ali, Hamza, and Danish 

Aquí está mi enfoque para lograr este comportamiento.

Para una solución más completa que incluya ILookup , revisa mi otra respuesta .

 public abstract class Lookup : KeyedCollection> { protected override TKey GetKeyForItem(ICollection item) => item .Select(b => GetKeyForItem(b)) .Distinct() .SingleOrDefault(); protected abstract TKey GetKeyForItem(TElement item); public void Add(TElement item) { var key = GetKeyForItem(item); if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)) collection.Add(item); else Add(new List { item }); } public void Remove(TElement item) { var key = GetKeyForItem(item); if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)) { collection.Remove(item); if (collection.Count == 0) Remove(key); } } } 

Uso:

 public class Item { public string Key { get; } public string Value { get; set; } public Item(string key, string value = null) { Key = key; Value = value; } } public class Lookup : Lookup { protected override string GetKeyForItem(Item item) => item.Key; } static void Main(string[] args) { var toRem = new Item("1", "different"); var single = new Item("2", "single"); var lookup = new Lookup() { new Item("1", "hello"), new Item("1", "hello2"), new Item(""), new Item("", "helloo"), toRem, single }; lookup.Remove(toRem); lookup.Remove(single); } 

Nota: la clave debe ser inmutable (o eliminar y volver a agregar al cambiar la tecla).

También puedes usar;

  List> Mappings; 

Puede crear un multi-diccionario muy simplista, que automatiza el proceso de inserción de valores como este:

 public class MultiDictionary : Dictionary> { public void Add(TKey key, TValue value) { if (TryGetValue(key, out List valueList)) { valueList.Add(value); } else { Add(key, new List { value }); } } } 

Esto crea una versión sobrecargada del método Add . El original le permite insertar una lista de elementos para una clave, si aún no existe una entrada para esta entrada. Esta versión le permite insertar un solo elemento en cualquier caso.