Something like this should work (you need to get the ValueTuple NuGet package for that tuple call signature to work):
public static IEnumerable<int> ListOfInts = new List<int> { 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5 };
public static (int? mostFrequent, int numOccurances) FindMostFrequent(IEnumerable<int> ints) {
int maxNumOccurances = int.MinValue;
int? mostFrequent = null;
//key is number (that occurs), value is number of occurances
var counters = new Dictionary<int, int>();
foreach (var num in ints) {
if (counters.TryGetValue(num, out var occurances)) {
counters[num] = ++occurances;
} else {
counters[num] = 1;
}
if (occurances > maxNumOccurances) {
mostFrequent = num;
maxNumOccurances = occurances;
}
}
return (mostFrequent, maxNumOccurances);
}
It goes through the integer collection once. It builds a Dictionary<int, int> as it walks through the list, doing N lookups and N writes (either inserts or replacements).
If the list is empty, the mostFrequent part of the return will be null. If there the maximum occurs more than once, you'll get the first one that's found. If you want the last, change the > to >= in:
if (occurances > maxNumOccurances)
and, if you want all possible results, do something like this before the return:
var maxes = from pair in counters where pair.Value == maxNumOccurances select pair;