À partir de la version 3.5+ de .NET, au lieu d'utiliser une balise Dictionary<IKey, List<IValue>>
vous pouvez utiliser un Lookup
de l'espace de noms LINQ :
// Lookup Order by payment status (1:m)
// would need something like Dictionary<Boolean, IEnumerable<Order>> orderIdByIsPayed
ILookup<Boolean, Order> byPayment = orderList.ToLookup(o => o.IsPayed);
IEnumerable<Order> payedOrders = byPayment[false];
De MSDN :
Une Lookup<TKey, TElement> ressemble à un Dictionary<TKey, TValue>. La différence avec différence est qu'un Dictionary<TKey, TValue> fait correspondre les clés à des valeurs uniques, alors qu'une Lookup<TKey, TElement> fait correspondre les clés à des collections de valeurs.
Vous pouvez créer une instance d'une Lookup<TKey, TElement> en appelant ToLookup sur un objet qui implémente IEnumerable.
Vous pouvez également lire cette réponse à un Question connexe . Pour plus d'informations, consultez MSDN .
Exemple complet :
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqLookupSpike
{
class Program
{
static void Main(String[] args)
{
// Init
var orderList = new List<Order>();
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<Int32, Order> orders = orderList.ToDictionary(o => o.OrderId, o => o);
// Lookup Order by customer (1:n)
// would need something like Dictionary<Int32, IEnumerable<Order>> orderIdByCustomer
ILookup<Int32, Order> 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<Int32, List<Order>> 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<Boolean, IEnumerable<Order>> orderIdByIsPayed
ILookup<Boolean, Order> byPayment = orderList.ToLookup(o => o.IsPayed);
IEnumerable<Order> 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<OrderItem> _items;
public Order(Int32 orderId, Int32 customerId, Int32 year, Boolean isPayed)
{
OrderId = orderId;
CustomerId = customerId;
Year = year;
IsPayed = isPayed;
}
}
}
}
Remarque sur l'immuabilité
Par défaut, consultations sont en quelque sorte immuables et l'accès aux internal
impliquerait une réflexion. Si vous avez besoin de la mutabilité et que vous ne voulez pas écrire votre propre wrapper, vous pouvez utiliser MultiValueDictionary
(anciennement connu sous le nom de MultiDictionary
) de corefxlab (qui faisait auparavant partie de Microsoft.Experimental.Collections
qui n'est plus mis à jour).