一个字符串数组中,一个字符出现的最大次数是多少?

4
在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>上工作?

3个回答

8

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

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


啊,你刚好比我快。 - krillgar

1
你可以像这样编写代码。注意使用 DefaultIfEmpty,以避免在 myStrings 为空时抛出异常,而是恢复为 0
var maximum = myStrings.Select(e => e.Count(ee => ee == '#')).DefaultIfEmpty().Max();

0
你可以使用 Linq 结合 Regex 来实现这个功能:
myStrings.Select(x => Regex.Matches(x, "#").Count).max();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接