字符在字符串数组中出现的最大出现次数

本文关键字:数组 字符 字符串 | 更新日期: 2023-09-27 18:32:24

在 C# 中,给定数组:

string[] myStrings = new string[] {
  "test#test",
  "##test",
  "######", // Winner (outputs 6)
};

如何找到字符#在单个字符串中出现的最大出现次数?

我目前的解决方案是:

int maxOccurrences = 0;
foreach (var myString in myStrings)
{
    var occurrences = myString.Count(x => x == '#');
    if (occurrences > maxOccurrences)
    {
        maxOccurrences = occurrences;
    }
}
return maxOccurrences;

他们使用linq可以直接作用于myStrings[]数组的更简单方法吗?

这可以变成一种可以在任何IEnumerable<string>上工作的扩展方法吗?

字符在字符串数组中出现的最大出现次数

首先,让我们将字符串投影到一个包含匹配计数的序列中:

myStrings.Select(x => x.Count(x => x == '#')) // {1, 2, 6} in your example

然后选择最大值:

int maximum = myStrings
    .Select(s => s.Count(x => x == '#'))
    .Max(); // 6 in your example

让我们做一个扩展方法:

public static int CountMaximumOccurrencesOf(this IEnumerable<string> strings, char ch)
{
    return strings
        .Select(s => s.Count(c => c == ch))
        .Max();
}
然而,

有一个很大的然而。在 C# 中,你所说的char不是你语言中所说的字符。这在其他帖子中已经广泛讨论,例如:将大文本拆分为较小块的最快方法和如何逐字符比较执行 Unicode 感知字符?那我就不在这里重复了。要"了解 Unicode",您需要使您的代码更加复杂(请注意,代码是写在这里的,然后未经测试):

private static IEnumerable<string> EnumerateCharacters(string s)
{
    var enumerator = StringInfo.GetTextElementEnumerator(s.Normalize());
    while (enumerator.MoveNext())
        yield return (string)enumerator.Value;
}

然后将我们的原始代码更改为:

public static int CountMaximumOccurrencesOf(this IEnumerable<string> strings, string character)
{
    return strings
        .Select(s => s.EnumerateCharacters().Count(c => String.Equals(c, character, StringComparison.CurrentCulture))
        .Max();
}

请注意,仅Max()要求集合不为空(如果集合可能为空并且不是错误,请使用DefaultIfEmpty())。为了不随意决定在这种情况下要做什么(如果应该发生或只返回 0),您可以降低此方法的专业化程度,并将此责任留给调用方:

public static int CountOccurrencesOf(this IEnumerable<string> strings,
    string character,
    StringComparison comparison = StringComparison.CurrentCulture)
{
    Debug.Assert(character.EnumerateCharacters().Count() == 1);
    return strings
        .Select(s => s.EnumerateCharacters().Count(c => String.Equals(c, character, comparison ));
}

像这样使用:

var maximum = myStrings.CountOccurrencesOf("#").Max();

如果需要不区分大小写:

var maximum = myStrings.CountOccurrencesOf("à", StringComparison.CurrentCultureIgnoreCase)
    .Max();

正如您现在可以想象的那样,这种比较不仅限于某些深奥的语言,而且还适用于固定区域性 (en-US),那么对于必须始终与固定区域性进行比较的字符串,您应该指定StringComparison.InvariantCulture 。不要忘记,您可能还需要调用String.Normalize()输入字符。

你可以写这样的东西。请注意 DefaultIfEmpty 的用法,以便在myStrings为空时不抛出异常,而是恢复为 0

var maximum = myStrings.Select(e => e.Count(ee => ee == '#')).DefaultIfEmpty().Max();

你可以将Linq组合到Regex

myStrings.Select(x => Regex.Matches(x, "#").Count).max();