Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare/count values in a System.Collections.ArrayList

I'm scrubbing 5 files for a specific value. I dont anticipate any different values, BUT since this is for my own educational purposes, I would like the application to count, compare and print the most popular value.

for example:

ArrayList arrName = new ArrayList();
arrName.Add("BOB")
arrName.Add("JOHN")
arrName.Add("TOM")
arrName.Add("TOM")
arrName.Add("TOM")

The result I would like is going to be TOM but being a novice, I really dont know how to move forward.

Any thoughts, suggestions or examples are greatly appreciated. Thank you.

like image 757
Leroy Jenkins Avatar asked Jan 24 '10 05:01

Leroy Jenkins


2 Answers

You can easily do this with LINQ if you can use it, with a query similar to

names.Distinct().OrderByDescending(s => names.Count(u => u == s))).FirstOrDefault();

It will return the value with the highest count, or default(Type). In cases of equivalent counts, it will return the first one with he highest count. You can put that method in your extensions with generics for general usage.

class Program
{
    static void Main(string[] args)
    {

        IEnumerable<String> names = new String[] { "BOB", 
                                                   "JOHN", 
                                                   "TOM", 
                                                   "TOM", 
                                                   "TOM" };
        var res = names.Top(); //returns "TOM"
    }
}

public static class Extensions
{

    public static T Top<T>(this IEnumerable<T> values)
    {
        return values.Distinct().OrderByDescending(s => values.Count(u => u.Equals(s))).FirstOrDefault();
    }
}

If you need all values that have the highest count, like if your list was "BOB", "JOHN", "JOHN", "TOM", "TOM" I guess you could use this version instead in order to return both JOHN and TOM:

    public static IEnumerable<T> Top<T>(this IEnumerable<T> values)
    {
        List<T> ret = new List<T>();
        int max = -1;

        foreach (var val in values.Distinct())
        {
            int count = values.Count(t => t.Equals(val));

            if (count >= max)
            {
                if (count > max)
                {
                    ret.Clear();
                    max = count;
                }
                ret.Add(val); //stacks equivalent count, if applicable
            }
        }

        return ret;
    }
like image 92
Dynami Le Savard Avatar answered Nov 06 '22 01:11

Dynami Le Savard


You didn't specify the version of .Net / C# you are using, so I'll treat this for each version of C#: v1, v2 and v3.

C# V1:

class CountValueComparer : IComparer
{
    public int Compare(object x, object y)
    {
        DictionaryEntry left = (DictionaryEntry)x;
        DictionaryEntry right = (DictionaryEntry)y;

        return ((int)left.Value).CompareTo((int)right.Value);
    }
}

Hashtable counts = new Hashtable();

foreach(String value in arrName)
{
    if (counts.ContainsKey(value))
    {
        int valueCount = (int)counts[value];
        ++valueCount;
        counts[value] = valueCount;
    }
    else
    {
        counts[value] = 1;
    }
}

DictionaryEntry[] sorted = new DictionaryEntry[counts.Count];
counts.CopyTo(sorted, 0);
Array.Sort(sorted, new CountValueComparer());

foreach (DictionaryEntry entry in sorted)
{
    Console.Writeline("Name: {0}; Count: {1}", entry.Key, entry.Value);
}

C# V2:

class CountValueComparer : IComparer<KeyValuePair<String, int>>
{
    public int Compare(int x, int y)
    {
        return x.Value.CompareTo(y.Value);
    }
}

// if v2, use the List<T> class!
List<String> arrName = new List<String>();

arrName.Add("TOM");
// etc...

Dictionary<String, int> counts = new Dictionary<String, int>();

foreach(String value in arrName)
{
    int count;
    if (counts.TryGetValue(value, out count))
    {
        counts[value] = ++count;
    }
    else
    {
        counts[value] = 1;
    }
}

KeyValuePair<String, int>[] sorted = new KeyValuePair<String, int>[counts.Count];
counts.CopyTo(sorted, 0);
Array.Sort(sorted, new CountValueComparer());

C# V3:

// if v3, use the List<T> class!
var arrName = new List<String>();

arrName.Add("TOM");
// etc...

var counts = (from n in arrName 
              group n by n into g 
              select new { Name = g.Key, Count = g.Count() })
              .OrderByDescending(x => x.Count);
var top = counts.FirstOrDefault();
Console.WriteLine("Name: {0}; Count: {1}", top.Name, top.Count);
like image 22
codekaizen Avatar answered Nov 06 '22 00:11

codekaizen