在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>
上使用的扩展方法吗?
答案 0 :(得分: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();
}
然而,有一个很大的 HOWEVER 。你在C#中调用char
的内容并不是你用你的语言称之为字符的内容。这已在其他帖子中广泛讨论,例如:Fastest way to split a huge text into smaller chunks和How can I perform a Unicode aware character by character comparison?然后我不会在此重复所有内容。成为&#34; Unicode感知&#34;你需要让你的代码更复杂(请注意代码写在这里,然后它未经测试):
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()
。
答案 1 :(得分:1)
你可以写这样的东西。请注意DefaultIfEmpty
的使用情况,如果myStrings
为空,则不会抛出异常,但会恢复为0
。
var maximum = myStrings.Select(e => e.Count(ee => ee == '#')).DefaultIfEmpty().Max();
答案 2 :(得分:0)
您可以将Linq
合并到Regex
:
myStrings.Select(x => Regex.Matches(x, "#").Count).max();