12

I have an array which contains the following results

red 
red
red
blue
blue
Green
White
Grey

and I want to get duplicate count of every value of array, for example:

red    Count=3
blue   Count=2
Green  Count=1
White  Count=1
Grey   Count=1
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Ahsan Attari
  • 987
  • 3
  • 12
  • 26
  • The similar question is here http://stackoverflow.com/questions/454601/how-to-count-duplicates-in-list-with-linq – andrew Oct 20 '11 at 07:47
  • 1
    Is this site turning into "I have a homework, send me the code" thing? – Karel Frajták Oct 20 '11 at 07:48
  • @Frederik Mörk are you sure the op did not mean `" red", " red ", " \t\tred"` as his/her strings? (I assume you deleted those white-spaces). I know that you can just Trim those, but Im not sure the op knows too. – e-MEE Oct 20 '11 at 07:49
  • @e-MEE Apparently not, because "red Count=3" – Tadeusz Oct 20 '11 at 07:55

7 Answers7

34

LINQ makes this easy:

Dictionary<string, int> counts = array.GroupBy(x => x)
                                      .ToDictionary(g => g.Key,
                                                    g => g.Count());
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    LINQ has conquered the World. – Tadeusz Oct 20 '11 at 07:51
  • In one line of code you've just obliterated everyone else's answer :) – slugster Oct 20 '11 at 08:05
  • In addition would it be possible to get the duplicate indexes as well? Thanks for your answer. – One-One Jun 26 '12 at 05:29
  • @desaivv: It would be possible, via a call to `Select` to start with which would provide `(value, index)` pairs. It wouldn't look pretty though. – Jon Skeet Jun 26 '12 at 05:42
  • This is a nice solution. Is there anyway do use this same method if the string is an object and you want to group by multiple fields of the object ? – blueprintchris Apr 28 '17 at 14:57
  • @blueprintChris: Well you can use `GroupBy(x => new { x.Name, x.Age })` instead... if that's not enough for what you want, please ask a new question. – Jon Skeet Apr 28 '17 at 15:09
  • I've tried that but the IDE complains about returning an anonymous type... I would ask a new question but my work blocks me from doing so... Any suggestions? – blueprintchris Apr 28 '17 at 15:13
  • @blueprintChris: Wait until you get home to ask a new question. – Jon Skeet Apr 28 '17 at 15:22
1

a little error above, right code is:

string[] arr = { "red", "red", "blue", "green", "Black", "blue", "red" };

var results = from str in arr
              let c = arr.Count( m => str.Contains(m.Trim()))
              select str + " count=" + c;

foreach(string str in results.Distinct())
    Console.WriteLine(str);
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
1

Add them to a Dictionary:

Dictionary<string, int> counts = new Dictionary<string, int>();
foreach(string s in list) 
{
   int prevCount;
   if (!counts.TryGet(s, out prevCount))
   {
      prevCount.Add(s, 1);
   }
   else
   {   
       counts[s] = prevCount++;
   }
}

Then counts contains the strings as keys, and their occurence as values.

Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
Anders Forsgren
  • 10,827
  • 4
  • 40
  • 77
1

Hmm That is a very hard task, but Captain Algorithm will help you! He is telling us that there are many ways to do this. One of them he give me and I give it to you:

Dictionary <object, int> tmp = new Dictionary <object, int> ();

foreach (Object obj in YourArray)
  if (!tmp.ContainsKey(obj))
    tmp.Add (obj, 1);
 else tmp[obj] ++;

tmp.Values;//Contains counts of elements
Tadeusz
  • 6,453
  • 9
  • 40
  • 58
0
Hashtable ht = new Hashtable();
foreach (string s in inputStringArray)
{
    if (!ht.Contains(s))
    {
        ht.Add(s, 1);
    }
    else
    {
        ht[s] = (int)ht[s] + 1;
    }
}
Tshilidzi Mudau
  • 7,373
  • 6
  • 36
  • 49
Michal M
  • 11
  • 3
0

make another array of counts ....and loop on the original array putting a condition that if it found red increment the 1st cell of the count array ...if it found blue increment the second cell in the count array ....etc. Good Luck .

-1

I think this should do the trick

    string[] arr = { "red", "red", "blue", "green", "Black", "blue", "red" };

    var results = from str in arr
                  let c = arr.Count( m => str.Contains(m.Trim()))
                  select str + " count=" + str;

    foreach(string str in results.Distinct())
        Console.WriteLine(str);

Output:

red count=3
blue count=2
green count=1
Black count=1
user529213
  • 24
  • 2
  • -1: convoluted, and I see no reason to hurt performance by concatenate strings in the intermediate step. – ANeves Oct 20 '11 at 08:03