AwesomeGuy
AwesomeGuy

Reputation: 547

LINQ group by multiple attributes and create dictionary

I have a list of objects from a class called ScrewBoltPattern.

I want to create a dictionary which contains the number of appearances of each family of ScrewBoltPattern. To decide if a screw belongs to a family I use some properties of that class.

To simplify this query let's say I use the properties Length and Diameter.

I want to create a Dictionary which has keys formatted like screw.Length + "_" + screw.Diameter

How can I get this?

This is what I've done so far

Dictionary<string, int> boltFamilyList = selectedBolts
                .GroupBy(bolt => new { bolt.Length, bolt.Diameter })
                .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

I need to give format to the dictionary key somewhere, but I don't know how to do it.

Upvotes: 3

Views: 3882

Answers (4)

Johnny
Johnny

Reputation: 9519

Although you already have the solution, just want to point how you could solve it because you were really close to the solution...

Dictionary<string, int> boltFamilyList = selectedBolts
    .GroupBy(bolt => new { bolt.Length, bolt.Diameter })
    .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

in the list line you could create key:

.ToDictionary(bolt => $"{bolt.Key.Length}_{bolt.Key.Diameter}", bolt => bolt.Count());

If you look at the signature of the Enumerable.ToDictionary method you will see that the first argument is Func<TSource,TKey> keySelector, in your case the TSource is anonymous type and the TKey is string. All you need to do is to define mapping between TSource and TKey and that is exactly what the function bolt => $"{bolt.Key.Length}_{bolt.Key.Diameter}" does.

Upvotes: 1

M.kazem Akhgary
M.kazem Akhgary

Reputation: 19149

You may not be aware of this solution as well, you may not need string formatting at all. (you can use C# 7 with value tuples)

Dictionary<(int length, int diameter), int> boltFamilyList = selectedBolts
    .GroupBy(bolt => (bolt.Length, bolt.Diameter))
    .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

And access like

dic.TryGetValue((10, 20), out int count);

Where 10 and 20 are length and diameter

Upvotes: 1

ProgrammingLlama
ProgrammingLlama

Reputation: 38767

You can format the key in the group by:

Dictionary<string, int> boltFamilyList = selectedBolts
    .GroupBy(bolt => $"{bolt.Length}_{bolt.Diameter}")
    .ToDictionary(bolt => bolt.Key, bolt => bolt.Count());

Your group key (and by proxy your dictionary key) will be that formatted string.

Try it online

Upvotes: 5

vc 74
vc 74

Reputation: 38179

You can also use an ILookup to achieve the same goal:

ILookup<string, int> lookup = 
    selectedBolts.ToLookup(bolt => $"{bolt.Length}_{bolt.Diameter}");

and then

int count = lookup["12_36"].Count();

Upvotes: 4

Related Questions