Encuentra el personaje con la mayoría de las ocurrencias en una cadena con C #?

Por ejemplo, tengo una cadena:

"abbbbccd" 

b tiene la mayor cantidad de ocurrencias. Al usar C ++, la forma más fácil de manejar esto es insertando cada carácter en un map . ¿Tengo que hacer lo mismo en C #? ¿Hay una manera elegante de hacerlo usando LINQ?

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

Notas:

  • si necesita esto para trabajar en versiones antiguas (2.0) de .Net considere LinqBridge . Si no puede usar C # 3.0 (orientación .Net 2.0), probablemente sea mejor con otras soluciones debido a la falta de compatibilidad con lambda. Otra opción .Net 2.0+ está cubierta en xanatos answer .
  • para el caso de "aaaabbbb" solo se "aaaabbbb" uno de ellos (gracias xanatos para comentar). Si necesita todos los elementos con el recuento máximo, use la solución de Albin en su lugar.
  • debido a la clasificación de esto si la solución O (n log n). Si necesita algo mejor que eso, busque el valor Máx. Por búsqueda lineal en lugar de ordenar primero, lo que dará O (n). Vea LINQ: Cómo realizar .Max () en una propiedad de todos los objetos en una colección y devolver el objeto con el valor máximo

Esto porque alguien pidió una versión 2.0, entonces no hay 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); } } 

En cambio esto para la versión LINQ. Extraerá los “mejores” pares (aaaabbbb == a, b). NO funcionará si 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); } 

Inspirado por la respuesta de Stephen, casi lo mismo:

 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 } 

Actualización: ¿Hizo una evaluación comparativa rápida de esta respuesta contra la respuesta de Jodrell (versión de lanzamiento, depurador separado, oh sí)

source = “”;

iteraciones = 1000000

resultado:

 this - 280 ms Jodrell's - 900 ms 

source = “aabc”;

iteraciones = 1000000

resultado:

 this - 1800 ms Jodrell's - 3200 ms 

fuente = cadena bastante grande – 3500+ caracteres

iteraciones = 10000

resultado:

 this - 3200 ms Jodrell's - 3000 ms 

EDIT 3

Aquí está mi última respuesta, que creo (simplemente) sombrea la de Nawfal para el rendimiento en secuencias más largas.

Sin embargo, dada la complejidad reducida de la respuesta de Nawfal y su desempeño más universal, especialmente en relación con la pregunta, elegiría eso.

 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); } 

EDIT 2


EDITAR



Si desea una solución genérica eficiente, que tenga en cuenta el hecho de que varios elementos pueden tener la misma frecuencia, comience con esta extensión,

 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); } 

Esta extensión funciona en todos los siguientes escenarios

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

o,

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

Tenga en cuenta que mostFrequent es un KeyValuePair> .


Si es así, podría simplificar esto a otra extensión,

 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); } 

que obviamente podría usarse así,

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

aquí, la mostFrequent es un IEnumerable .

Encuentra la función más simple y sin función incorporada utilizada

código de muestra y enlaces

 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; } 

Sepa más sobre cómo obtener la máxima incidencia y cuál es el flujo.

Cómo obtener el máximo carácter y la ocurrencia máxima en cadena

Esta es la solución de Femaref modificada para devolver varias letras si su Cuenta coincide. Ya no es un trazador de líneas, pero aún así es bastante conciso.

 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); 

Después de la discusión con 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); } } 

Código:

 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();