使用C#查找字符串中出现次数最多的字符?

例如,我有一个字符串:

"abbbbccd" 

b出现次数最多。 使用C ++时,处理此问题的最简单方法是将每个字符插入到map 。 我是否必须在C#中做同样的事情? 使用LINQ有一种优雅的方式吗?

 input.GroupBy(x => x).OrderByDescending(x => x.Count()).First().Key 

笔记:

  • 如果你需要这个工作在.Net的古代(2.0)版本考虑LinqBridge 。 如果您不能使用C#3.0(针对.Net 2.0),由于缺少lambda支持,您可能最好使用其他解决方案。 xanatos答案涵盖了另一个.Net 2.0+选项。
  • 对于"aaaabbbb"的情况,只返回其中一个(感谢xanatos评论)。 如果您需要所有具有最大计数的元素,请使用Albin的解决方案 。
  • 由于排序这个如果O(n log n)解决方案。 如果你需要更好 – 通过线性搜索找到最大值而不是先排序,这将给出O(n)。 请参阅LINQ:如何对集合中所有对象的属性执行.Max()并返回具有最大值的对象

这是因为有人要求提供2.0版本,所以没有LINQ。

 Dictionary dict = new Dictionary(); int max = 0; foreach (char c in "abbbbccccd") { int i; dict.TryGetValue(c, out i); i++; if (i > max) { max = i; } dict[c] = i; } foreach (KeyValuePair chars in dict) { if (chars.Value == max) { Console.WriteLine("{0}: {1}", chars.Key, chars.Value); } } 

相反,这适用于LINQ版本。 它将提取成对的“bests”(aaaabbbb == a,b)。 如果str == String.Empty,它将无法工作。

 var str = "abbbbccccd"; var res = str.GroupBy(p => p).Select(p => new { Count = p.Count(), Char = p.Key }).GroupBy(p => p.Count, p => p.Char).OrderByDescending(p => p.Key).First(); foreach (var r in res) { Console.WriteLine("{0}: {1}", res.Key, r); } 
 string testString = "abbbbccd"; var charGroups = (from c in testString group c by c into g select new { c = g.Key, count = g.Count(), }).OrderByDescending(c => c.count); foreach (var group in charGroups) { Console.WriteLine(group.c + ": " + group.count); } 

灵感来自斯蒂芬的回答,几乎相同:

 public static IEnumerable Mode(this IEnumerable input) { var dict = input.ToLookup(x => x); if (dict.Count == 0) return Enumerable.Empty(); var maxCount = dict.Max(x => x.Count()); return dict.Where(x => x.Count() == maxCount).Select(x => x.Key); } var modes = "".Mode().ToArray(); //returns { } var modes = "abc".Mode().ToArray(); //returns { a, b, c } var modes = "aabc".Mode().ToArray(); //returns { a } var modes = "aabbc".Mode().ToArray(); //returns { a, b } 

更新:对Jodrell的答案(发布构建,调试器分离,哦是)快速进行了这个答案的基准测试

source =“”;

迭代= 1000000

结果:

 this - 280 ms Jodrell's - 900 ms 

source =“aabc”;

迭代= 1000000

结果:

 this - 1800 ms Jodrell's - 3200 ms 

source =相当大的字符串 – 3500+ char

迭代= 10000

结果:

 this - 3200 ms Jodrell's - 3000 ms 

编辑3

这是我的最后一个答案,我认为(只是)将Nawfal用于较长序列的表现。

然而,鉴于Nawfal答案的复杂性降低,以及其更普遍的表现,尤其是与问题相关的问题,我会选择它。

 public static IEnumerable Mode( this IEnumerable source, IEqualityComparer 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(); } var maxes = new List(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); } 

编辑2


编辑



如果您想要一个有效的通用解决方案,这可以解释多个项目可能具有相同频率的事实,请从此扩展开始,

 IOrderedEnumerable>>Frequency( this IEnumerable source, IComparer comparer = null) { return source.GroupBy(t => t, comparer) .GroupBy( g => g.Count(), (k, s) => new KeyValuePair>( k, s.Select(g => g.First()))) .OrderByDescending(f => f.Key); } 

此扩展适用于以下所有方案

 var mostFrequent = string.Empty.Frequency().FirstOrDefault(); var mostFrequent = "abbbbccd".Frequency().First(); 

要么,

 var mostFrequent = "aaacbbbcdddceee".Frequency().First(); 

请注意, mostFrequentKeyValuePair>


如果有这样的想法,你可以将其简化为另一个扩展,

 public static IEnumerable Mode( this IEnumerable source, IEqualityComparer 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() : mode.Select(g => g.Value); } 

显然可以这样使用,

 var mostFrequent = string.Empty.Mode(); var mostFrequent = "abbbbccd".Mode(); var mostFrequent = "aaacbbbcdddceee".Mode(); 

这里, mostFrequent是一个IEnumerable

找到最简单的,没有使用的内置函数

示例代码和链接

 public char MostOccurringCharInString(string charString) { int mostOccurrence = -1; char mostOccurringChar = ' '; foreach (char currentChar in charString) { int foundCharOccreence = 0; foreach (char charToBeMatch in charString) { if (currentChar == charToBeMatch) foundCharOccreence++; } if (mostOccurrence < foundCharOccreence) { mostOccurrence = foundCharOccreence; mostOccurringChar = currentChar; } } return mostOccurringChar; } 

了解更多关于如何获得最大值以及流量的信息。

如何获得字符串中出现的最大字符数和最大值

这是Femaref的解决方案,如果他们的Count匹配则修改为返回多个字母。 它不再是单行,但仍然相当简洁。

 var groups = "aaaabbbbccd".GroupBy(x => x).Select(x => new { Letter = x.Key, Count = x.Count() }).ToList(); return groups.Where(g => g.Count == groups.Max(g2 => g2.Count)).Select(g => g.Letter); 

与nawfal讨论后:

 void Main() { "aaaabbhbbxh".GetMostFrequentCharacters().Dump(); ((string)null).GetMostFrequentCharacters().Dump(); " ".GetMostFrequentCharacters().Dump(); "".GetMostFrequentCharacters().Dump(); } static class LinqPadExtensions { public static IEnumerable GetMostFrequentCharacters(this string str) { if (string.IsNullOrEmpty(str)) return Enumerable.Empty(); 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); } } 

码:

 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 count = chararr.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); foreach(KeyValuePair key in count) { Console.WriteLine("Occurrence of {0}: {1}",key.Key,key.Value); } Console.ReadLine(); } } 
  //find most occuring character and count from below string string totest = "abcda12Zernn111y"; string maxOccuringCharacter = ""; int maxOccurence = 0;string currentLoopCharacter = ""; string updatedStringToTest = "";int cnt = 0; for (int i = 0; i < totest.Length; i++) { currentLoopCharacter = totest[i].ToString(); updatedStringToTest = totest.Replace(currentLoopCharacter, ""); cnt = totest.Length - updatedStringToTest.Length; if (cnt > maxOccurence) { maxOccuringCharacter = currentLoopCharacter; maxOccurence = cnt; } totest = updatedStringToTest; } Console.WriteLine("The most occuring character is {0} and occurence was {1}", maxOccuringCharacter, maxOccurence.ToString()); Console.ReadLine(); 
 #simplified expression using LINQ# string text = "abccdeeef"; int length = text.ToCharArray().GroupBy(x => x).OrderByDescending(x => x.Count()).First().Count();