For example, I have a string:
\"abbbbccd\"
b
has the most occurrences. When using C++, the easiest way to handle this is inser
input.GroupBy(x => x).OrderByDescending(x => x.Count()).First().Key
Notes:
"aaaabbbb"
only one of those will be returned (thanks xanatos for comment). If you need all of the elements with maximum count, use Albin's solution instead.Code:
class CharCount
{
public void CountCharacter()
{
int n;
Console.WriteLine("enter the no. of elements: ");
n = Convert.ToInt32(Console.ReadLine());
char[] chararr = new char[n];
Console.WriteLine("enter the elements in array: ");
for (int i = 0; i < n; i++)
{
chararr[i] = Convert.ToChar(Console.ReadLine());
}
Dictionary<char, int> count = chararr.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
foreach(KeyValuePair<char, int> key in count)
{
Console.WriteLine("Occurrence of {0}: {1}",key.Key,key.Value);
}
Console.ReadLine();
}
}
EDIT 3
Here is my last answer which I think (just) shades Nawfal's for performance on longer sequences.
However, given the reduced complexity of Nawfal's answer, and its more universal performance, especially in relation to the question, I'd choose that.
public static IEnumerable<T> Mode<T>(
this IEnumerable<T> source,
IEqualityComparer<T> comparer = null)
{
var counts = source.GroupBy(t => t, comparer)
.Select(g => new { g.Key, Count = g.Count() })
.ToList();
if (counts.Count == 0)
{
return Enumerable.Empty<T>();
}
var maxes = new List<int>(5);
int maxCount = 1;
for (var i = 0; i < counts.Count; i++)
{
if (counts[i].Count < maxCount)
{
continue;
}
if (counts[i].Count > maxCount)
{
maxes.Clear();
maxCount = counts[i].Count;
}
maxes.Add(i);
}
return maxes.Select(i => counts[i].Key);
}
EDIT 2
EDIT
If you want an efficient generic solution, that accounts for the fact that multiple items could have the same frequency, start with this extension,
IOrderedEnumerable<KeyValuePair<int, IEnumerable<T>>>Frequency<T>(
this IEnumerable<T> source,
IComparer<T> comparer = null)
{
return source.GroupBy(t => t, comparer)
.GroupBy(
g => g.Count(),
(k, s) => new KeyValuePair<int, IEnumerable<T>>(
k,
s.Select(g => g.First())))
.OrderByDescending(f => f.Key);
}
This extension works in all of the following scenarios
var mostFrequent = string.Empty.Frequency().FirstOrDefault();
var mostFrequent = "abbbbccd".Frequency().First();
or,
var mostFrequent = "aaacbbbcffffdceee".Frequency().First();
Note that mostFrequent
is a KeyValuePair<int, IEnumerable<char>>
.
If so minded you could simplify this to another extension,
public static IEnumerable<T> Mode<T>(
this IEnumerable<T> source,
IEqualityComparer<T> comparer = null)
{
var mode = source.GroupBy(
t => t,
(t, s) => new { Value = t, Count = s.Count() }, comparer)
.GroupBy(f => f.Count)
.OrderbyDescending(g => g.Key).FirstOrDefault();
return mode == null ? Enumerable.Empty<T>() : mode.Select(g => g.Value);
}
which obviously could be used thus,
var mostFrequent = string.Empty.Mode();
var mostFrequent = "abbbbccd".Mode();
var mostFrequent = "aaacbbbcffffdceee".Mode();
here, mostFrequent
is an IEnumerable<char>
.
This is Femaref's solution modified to return multiple letters if their Count matches. Its no longer a one-liner but still reasonably concise and should be fairly performant.
public static IEnumerable<char> GetMostFrequentCharacters(this string str)
{
if (string.IsNullOrEmpty(str))
return Enumerable.Empty<char>();
var groups = str.GroupBy(x => x).Select(x => new { Letter = x.Key, Count = x.Count() }).ToList();
var max = groups.Max(g2 => g2.Count);
return groups.Where(g => g.Count == max).Select(g => g.Letter);
}