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

MrD*_*per 4 c# linq extension-methods

在C#中,给出了数组:

string[] myStrings = new string[] {
  "test#test",
  "##test",
  "######", // Winner (outputs 6)
};
Run Code Online (Sandbox Code Playgroud)

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

我目前的解决方案是:

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

return maxOccurrences;
Run Code Online (Sandbox Code Playgroud)

使用可直接作用于myStrings[]阵列的linq是一种简单的方法吗?

这可以成为一个可以在任何方面工作的扩展方法IEnumerable<string>吗?

Adr*_*tti 8

首先,让我们将您的字符串投影到具有匹配数的序列中:

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

然后选择最大值:

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

让我们做一个扩展方法:

public static int CountMaximumOccurrencesOf(this IEnumerable<string> strings, char ch)
{
    return strings
        .Select(s => s.Count(c => c == ch))
        .Max();
}
Run Code Online (Sandbox Code Playgroud)

但是有一个很大的无论其.你打电话给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;
}
Run Code Online (Sandbox Code Playgroud)

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

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();
}
Run Code Online (Sandbox Code Playgroud)

请注意,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 ));
}
Run Code Online (Sandbox Code Playgroud)

像这样使用:

var maximum = myStrings.CountOccurrencesOf("#").Max();
Run Code Online (Sandbox Code Playgroud)

如果您需要它不区分大小写:

var maximum = myStrings.CountOccurrencesOf("à", StringComparison.CurrentCultureIgnoreCase)
    .Max();
Run Code Online (Sandbox Code Playgroud)

正如您现在可以想象的那样,这种比较并不局限于某些深奥的语言,但它也适用于不变文化(en-US),然后适用于必须始终与您应指定的不变文化进行比较的字符串StringComparison.InvariantCulture.不要忘记您可能还需要调用String.Normalize()输入字符.