Подтвердить что ты не робот

Найти символ с большинством вхождений в строку с С#?

Например, у меня есть строка:

"abbbbccd"

b имеет наибольшее количество вхождений. При использовании С++ самый простой способ справиться с этим - вставить каждый символ в map<>. Должен ли я делать то же самое в С#? Есть ли элегантный способ сделать это с помощью LINQ?

4b9b3361

Ответ 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();