121

I have the following object in a list:

public class DemoClass { public int GroupKey { get; set; } public string DemoString { get; set; } public object SomeOtherProperty { get; set; } } 

Now, I want to create following dictionary out of it:

Dictionary<int, List<DemoClass>> 

I want to group the List<DemoClass> by the property GroupKey, but I don't understand how this is done and some help.

After thinking a bit, I achieved the needed behaviour with:

var groupedDemoClasses = from demoClass in mySepcialVariableWhichIsAListOfDemoClass group demoClass by demoClass.GroupKey into groupedDemoClass select groupedDemoClass; var neededDictionary = groupedDemoClass.ToDictionary(gdc => gdc.Key, gdc => gdc.ToList()); 

but, is there a way to make this into a single statement?

4 Answers 4

221

Just to make mquander's suggestion concrete:

var groupedDemoClasses = mySpecialVariableWhichIsAListOfDemoClass .GroupBy(x => x.GroupKey) .ToDictionary(gdc => gdc.Key, gdc => gdc.ToList()); 

You'd make it shorter if you used shorter variable names too, of course :)

However, might I suggest that a Lookup might be more appropriate? A Lookup is basically a dictionary from a key to an IEnumerable<T> - unless you really need the values as a list, it makes the code even shorter (and more efficient) with the ToLookup call:

var groupedDemoClasses = mySpecialVariableWhichIsAListOfDemoClass .ToLookup(x => x.GroupKey); 
Sign up to request clarification or add additional context in comments.

8 Comments

i thought that a lookup performs not that good, compared to a built dictionary, in a longterm-environment, due it builds up the result fresh for every request... please correct me, if i'm wrong!
No, it creates the whole lookup. In general, ToXXX doesn't use deferred execution.
(You may be thinking of a Grouping, which is indeed deferred.)
If I wasn't so spiteful I'd vote you up. Came for the Linq, stayed for the data structure I've never heard of!
@sasikt: The model is that you can look up anything, and you just get an empty collection if the key doesn't exist. That's often more useful than the TryGetValue approach, IMO.
|
94
var groupedDemoClasses = (from demoClass in mySepcialVariableWhichIsAListOfDemoClass group demoClass by demoClass.GroupKey into groupedDemoClass select groupedDemoClass).ToDictionary(gdc => gdc.Key, gdc => gdc.ToList()); 

This one will work !!!

Comments

8

You already made it a one-liner. Just put the ToDictionary at the end of your first line. If you want it to be shorter, use the functional composition syntax instead of the query syntax.

Comments

4

I'm going slightly off topic here, but I got to this thread becausde I was looking for a way to create a dictionary of a dictionary in Linq, and the conversation here lead me to the answer...

You can use linq to create multi-level dictionaries, which is useful for scenarios where you've got more than 1 key or dimension that you want to search by. The trick is to create a grouping and then convert it to a dictionary, as follows:

 Dim qry = (From acs In ActualSales _ Group By acs.ProductID Into Group _ Select ProductID, Months = Group.ToDictionary(Function(c) c.Period) _ ).ToDictionary(Function(c) c.ProductID) 

The resulting query can be used as follows:

 If qry.ContainsKey(_ProductID) Then With qry(_ProductID) If .Months.ContainsKey(_Period) Then ... End If End With End If 

Hope this is helpful to anyone else who needs this sort of query.

Comments