Construyendo un diccionario de conteos de artículos en una lista

Tengo una lista que contiene un montón de cadenas que pueden aparecer más de una vez. Me gustaría tomar esta lista y crear un diccionario de los elementos de la lista como la clave y el recuento de sus ocurrencias como el valor.

Ejemplo:

List stuff = new List(); stuff.Add( "Peanut Butter" ); stuff.Add( "Jam" ); stuff.Add( "Food" ); stuff.Add( "Snacks" ); stuff.Add( "Philosophy" ); stuff.Add( "Peanut Butter" ); stuff.Add( "Jam" ); stuff.Add( "Food" ); 

y el resultado sería un Diccionario que contiene:

 "Peanut Butter", 2 "Jam", 2 "Food", 2 "Snacks", 1 "Philosophy", 1 

Tengo una manera de hacer esto, pero no parece que esté utilizando lo bueno en C # 3.0

 public Dictionary CountStuff( IList stuffList ) { Dictionary stuffCount = new Dictionary(); foreach (string stuff in stuffList) { //initialize or increment the count for this item if (stuffCount.ContainsKey( stuff )) { stuffCount[stuff]++; } else { stuffCount.Add( stuff, 1 ); } } return stuffCount; } 

Puede usar la cláusula de grupo en C # para hacer esto.

 List stuff = new List(); ... var groups = from s in stuff group s by s into g select new { Stuff = g.Key, Count = g.Count() }; 

También puede llamar directamente a los métodos de extensión si desea:

 var groups = stuff.GroupBy(s => s).Select( s => new { Stuff = s.Key, Count = s.Count() }); 

Desde aquí es un salto corto para colocarlo en un Dictionary :

 var dictionary = groups.ToDictionary(g => g.Stuff, g => g.Count); 

Hubiera hecho una Lista especializada, respaldada por el Diccionario y el método de adición probaría la membresía y boostía el conteo si se encontrara.

algo así como

 public class CountingList { Dictionary countingList = new Dictionary(); void Add( string s ) { if( countingList.ContainsKey( s )) countingList[ s ] ++; else countingList.Add( s, 1 ); } } 

Una idea sería darle al diccionario un valor predeterminado de cero, para que no tenga que hacer un caso especial la primera vez que ocurra.

Bueno, realmente no hay mejor manera de hacerlo.

Quizás podría escribir una consulta LINQ que agruparía las cadenas y luego contaría cuántas cadenas hay en cada grupo, pero eso no sería tan eficiente como lo que ya tiene.

 Dictionary a = stuff.GroupBy(p => p).OrderByDescending(r=>r.Count()).ToDictionary(q => q.Key, q => q.Count()); 

Puedes agrupar y luego crear un diccionario para contar cada grupo. Como lo indican las pruebas de rendimiento , usualmente hay enfoques más eficientes que Linq. Creo que su código es más eficiente, mientras que la solución Linq es más fácil de leer y hermosa.