Найти символ с большинством вхождений в строку с С#?
Например, у меня есть строка:
"abbbbccd"
b
имеет наибольшее количество вхождений. При использовании С++ самый простой способ справиться с этим - вставить каждый символ в map<>
. Должен ли я делать то же самое в С#? Есть ли элегантный способ сделать это с помощью LINQ?
Ответы
Ответ 1
input.GroupBy(x => x).OrderByDescending(x => x.Count()).First().Key
Примечания:
Ответ 2
Это потому, что кто-то попросил версию 2.0, поэтому LINQ.
Dictionary<char, int> dict = new Dictionary<char, int>();
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<char, int> 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);
}
Ответ 3
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);
}
Ответ 4
РЕДАКТИРОВАТЬ 3
Вот мой последний ответ, который я думаю (просто) оттеняет Nawfal для исполнения на более длинных последовательностях.
Однако, учитывая уменьшенную сложность ответа Nawfal и более универсальную производительность, особенно в связи с вопросом, я бы выбрал это.
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);
}
РЕДАКТИРОВАТЬ 2
ИЗМЕНИТЬ
Если вам требуется эффективное общее решение, это объясняет тот факт, что несколько элементов могут иметь одинаковую частоту, начните с этого расширения,
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);
}
Это расширение работает во всех следующих сценариях
var mostFrequent = string.Empty.Frequency().FirstOrDefault();
var mostFrequent = "abbbbccd".Frequency().First();
или,
var mostFrequent = "aaacbbbcdddceee".Frequency().First();
Обратите внимание, что mostFrequent
является KeyValuePair<int, IEnumerable<char>>
.
Если это так, вы можете упростить это для другого расширения,
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);
}
которые, очевидно, можно было бы использовать таким образом,
var mostFrequent = string.Empty.Mode();
var mostFrequent = "abbbbccd".Mode();
var mostFrequent = "aaacbbbcdddceee".Mode();
здесь mostFrequent
является IEnumerable<char>
.
Ответ 5
Вдохновленный от Стивена ответ, почти то же самое:
public static IEnumerable<T> Mode<T>(this IEnumerable<T> input)
{
var dict = input.ToLookup(x => x);
if (dict.Count == 0)
return Enumerable.Empty<T>();
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 }
Обновление: Прошел быстрый бенчмаркинг этого ответа vs ответ Jodrell (релиз сборки, отладчик отключен, о да)
source = "";
итерации = 1000000
результат:
this - 280 ms
Jodrell - 900 ms
source = "aabc";
итерации = 1000000
результат:
this - 1800 ms
Jodrell - 3200 ms
source = довольно большая строка - 3500+ char
итерации = 10000
результат:
this - 3200 ms
Jodrell - 3000 ms
Ответ 6
Найдите самую простую и без встроенной функции
пример кода и ссылок
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;
}
Узнайте больше о том, как получить максимальное появление и какой поток.
Как получить максимальный символ и максимальное вхождение в строке
Ответ 7
Это решение Femaref модифицировано для возврата нескольких букв, если их совпадение совпадает. Это уже не однострочный, но все же достаточно лаконичный.
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<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);
}
}
Ответ 8
Код:
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();
}
}
Ответ 9
//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();