【问题标题】:Maximum number of occurrences a character appears in an array of strings字符在字符串数组中出现的最大次数
【发布时间】:2016-01-29 15:22:01
【问题描述】:

在 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;

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

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

【问题讨论】:

    标签: c# linq extension-methods


    【解决方案1】:

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

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

    但是有一个很大的HOWEVER。在 C# 中你称之为 char 的东西不是你在语言中称之为字符的东西。这已经在其他帖子中广泛讨论过,例如:Fastest way to split a huge text into smaller chunksHow can I perform a Unicode aware character by character comparison? 然后我不会在这里重复所有内容。要“识别 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() 来输入字符。

    【讨论】:

    • 呸,快点打败我吧。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      您可以将LinqRegex 结合使用:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-06
        • 2013-05-23
        • 1970-01-01
        • 2011-04-03
        • 2021-03-19
        • 1970-01-01
        相关资源
        最近更新 更多