views:

154

answers:

4

I have a List containing a bunch of strings that can occur more than once. I would like to take this list and build a dictionary of the list items as the key and the count of their occurrences as the value.

Example:

List<string> stuff = new List<string>();
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" );

and the result would be a Dictionary containing:

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

I have a way to do this, but it doesn't seem like I'm utilizing the good stuff in C# 3.0

public Dictionary<string, int> CountStuff( IList<string> stuffList )
{
    Dictionary<string, int> stuffCount = new Dictionary<string, int>();

    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;
}
+1  A: 

One idea would be to give the dictionary a default value of zero, so you wouldn't have to special case the first occurrence.

MarkusQ
Well, that would just be moving the code that handles the special case into a separate class...
Guffa
+6  A: 

You can use the group clause in C# to do this.

List<string> stuff = new List<string>();
...

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

You can call the extension methods directly as well if you want:

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

You can put this into any other data structure, but the idea is that you use the group clause to get the items into a group and then work on the group from there.

casperOne
How would you add an orderby to the first example?
zadam
A: 

Well, there isn't really any better way to do it.

Perhaps you could write a LINQ query that would group the strings and then count how many strings there are in each group, but that would not be nearly as efficient as what you already have.

Guffa
+2  A: 

I would have made a specialized List, that backed by the Dictionary and the add method would test for membership and increase count if found.

sorta like:

public class CountingList
{
    Dictionary<string, int> countingList = new Dictionary<string, int>();

   void Add( string s )
   {
  if( countingList.ContainsKey( s ))
       countingList[ s ] ++;
     else
      countingList.Add( s, 1 );
   }
}
sfossen