score:5

Accepted answer

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

score:1

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.

score:1

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

score:4

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();

Related Query