Finding mode in List of integers

1.7k views Asked by At

How can I find the mode of a list of numbers? I know the logic of it (I think) but I don't know how to implement that logic or convert what my brain thinks into workable code.

This is what I know:

I need to have a loop that goes through the list one time to see how many times a number is repeated and an array to save the times a number is repeated. I also need to tell my program to discard the lesser amount once a larger one is found.

3

There are 3 answers

1
Yeldar Kurmangaliyev On

Yes, you are right:

Let we have a list of numbers:

List<int> myValues = new List<int>(new int[] { 1, 3, 3, 3, 7, 7 } );

You need to have a loop that goes through the list one time:

foreach (var val in myValues)
{
}

to see how many times a number is repeated in array to save the times a number is repeated:

Dictionary<int, int> repetitions = new Dictionary<int, int>(); 
foreach (var val in myValues)
{
    if (repetitions.ContainsKey(val))
        repetitions[val]++; // Met it one more time
    else
        repetitions.Add(val, 1); // Met it once, because it is not in dict. 
}

Now, your dictionary repetitions stores how many (exactly value) times key value repeated.
Then, you need to find the record of mode (i.e. record with the highest time of repetitions (i.e. highest value)) and take this one. LINQ will help us - let's sort the array by value and take the last one...or sort it descending and take the first one. Actually, that's the same in terms of result and productivity.

var modeRecord = repetitions.OrderByDescending(x => x.Value).First();
// or
var modeRecord = repetitions.OrderBy(x => x.Value).Last();

Here it is! Here we have a mode:

List<int> myValues = new List<int>(new int[] { 1, 3, 3, 3, 7, 7 } );
Dictionary<int, int> repetitions = new Dictionary<int, int>(); 

foreach (var val in myValues)
{
    if (repetitions.ContainsKey(val))
        repetitions[val]++; // Met it one more time
    else
        repetitions.Add(val, 1); // Met it once, because it is not in dict. 
}

var modeRecord = repetitions.OrderByDescending(x => x.Value).First();

Console.WriteLine("Mode is {0}. It meets {1} times in an list", modeRecord.Key, modeRecord.Value);

Your mode calculation logic is good. All you need is following your own instructions in a code :)

0
phoog On

A linq approach, more concise but almost certainly less efficient than Yeldar Kurmangaliyev's:

int FindMode(IEnumerable<int> data)
{
    return data
        .GroupBy(n => n)
        .Select(x => new { x.Key, Count = x.Count() })
        .OrderByDescending(a => a.Count)
        .First()
        .Key;
}

This does not handle the case where data is empty, nor where there are two or more data points with the same frequency in the data set.

0
Enigmativity On

Here's an alternative LINQ approach:

var values = new int[] { 1, 3, 3, 3, 7, 7 };

var mode =
    values
        .Aggregate(
            new { best = 0, best_length = 0, current = 0, current_length = 0 },
            (a, n) =>
            {
                var current_length = 1 + (a.current == n ? a.current_length : 0);
                var is_longer = current_length > a.best_length;
                return new
                {
                    best = is_longer ? n : a.best,
                    best_length = is_longer ? current_length : a.best_length,
                    current = n,
                    current_length,
                };
            }).best;