使用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();
请注意, mostFrequent
是KeyValuePair
。
如果有这样的想法,你可以将其简化为另一个扩展,
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();