IEnumerable<T> to Dictionary<string, IEnumerable<T>> using LINQ
Asked Answered
J

3

20

Having IEnumerable<Order> orders, how to get a Dictionary<string, IEnumerable<Order>> using Linq, where the key is Order.CustomerName mapped to a IEnumerable of customer's orders.

orders.ToDictionary(order => order.CustomerName) is not going to work right away, since there could be multiple orders that could have the same CustomerName.

Solution: orders.ToLookup(order => order.CustomerName);

Juggins answered 25/9, 2012 at 17:53 Comment(0)
D
34

The ILookup interface is designed for this purpose, and represents a dictionary-like structure that contains many values per key. It has similar performance characteristics to those of a dictionary (i.e. it's a hashtable type structure)

You can create an ILookup using the .ToLookup extension method as follows:

ILookup<string, Order> ordersLookup = orders.ToLookup(o => o.CustomerName)

then:

IEnumerable<Order> someCustomersOrders = ordersLookup[someCustomerName];
Decease answered 25/9, 2012 at 17:56 Comment(4)
+1 That's an awesome interface. Never heard of it before today.Shrovetide
Most people don't know about Lookups, but this is a great example of its use. This is preferable to a Dictionary with an enumerable as the value.Surely
@SimpleCoder it's used all over the place internally in Linq2ObjectsDecease
@spender: I'll have to check that out. Right now I'm working on a project that might benefit from ILookup, so I'll have to try it out.Shrovetide
U
13

Just an alternative to @spender's answer, if you really want a type Dictionary<string, IEnumerable<Order>>, you could use:

Dictionary<string, IEnumerable<Order>> dictionary = orders
        .GroupBy(order => order.CustomerName)
        .ToDictionary(groupedOrders => groupedOrders.Key, 
                          groupedOrders => (IEnumerable<Order>)groupedOrders);

I'm sure there's a nicer way, but that'll do it too.

Unhesitating answered 25/9, 2012 at 18:2 Comment(5)
Why? If you can do LINQ you can do ILookup, why re-invent a class that already exists in a library you are using to do the re-inventing.Reichenberg
@ScottChamberlain The key difference between an ILookup and a Dictionary is that the dictionary is mutable. If you need to change the result after creation you'll need to use a Dictionary (in this case the OP may want the immutable version though). It's also possible that there is an existing method/property typed as a Dictionary, and this needs to be passed into it.Cogitative
@ScottChamberlain - Well for one thing, the OP asked for a dictionary. Dictionary supports more operations than lookup (e.g. it can be modified), and it's possible the OP has some existing code which requires a dictionary.Flawed
@ScottChamberlain I would prefer the lookup case generally, perhaps even go from Lookup to Dictionary. @CuongLe, thanks for the edit; that's much better and I totally forgot about Key!Unhesitating
Ok, I understand now, however @Flawed I am doing some remodeling and I need to hammer a nail, should I use a Old Shoe or Glass Bottle?Reichenberg
B
5

Or you could probably simply use

orders.ToLookup(o => o.CustomerName).ToDictionary(g => g.Key)

But as Spender's answer indicates, maybe you don't need the last method, ToDictionary.

Bitstock answered 25/9, 2012 at 18:13 Comment(2)
FYI, this will create a Dictionary of type Dictionary<String, IGrouping<String,Order>>. Not sure if this is an issue for kateroh or not. +1 though for something concise.Unhesitating
That's correct. If you don't want that extra "structure" on the dictionary values, I guess you can say orders.ToLookup(o => o.CustomerName).ToDictionary<string, Order>(g => g.Key), if I'm turning the covariance of IEnumerable<> the right way inside my head.Bitstock

© 2022 - 2024 — McMap. All rights reserved.