在C#中计算大写字符数量的最快方法

17
这个的效率是多少?...
CommentText.ToCharArray().Where(c => c >= 'A' && c <= 'Z').Count()
6个回答

40

好的,我刚编写了一些代码来计算你的方法所需的时间:

int count = 0;
for (int i = 0; i < s.Length; i++)
{
    if (char.IsUpper(s[i])) count++;
}

结果:

你的: 19737 ticks

我的: 118 ticks

相差很大!有时候最直接的方式也是最有效的。

编辑

只是出于兴趣,这个:

int count = s.Count(c => char.IsUpper(c));

该操作大约需要2500个时钟周期。因此,对于使用Linq一行代码的操作来说,速度相当快。


糟糕!被人抢先了,解决方案几乎完全相同。干得好,马特,可恶的慢手指…… - Binary Worrier
顺便说一下,+1 伙计,你赚到了 :) - Binary Worrier
让它更快!通过修复指针来删除索引检查,然后如果您定义大写字母,那么您可能也可以摆脱该分支。即,如果大写字母-eq c> 0x60,则很容易,否则就比较棘手了。 - John Leidegren
1
但要注意的是,测试 (c => c >= 'A' && c <= 'Z') 并不等同于 (c => Char.IsUpper(c))。 - Tobias Hertkorn
1
@Matt s.Count(char.IsUpper)和s.Count(c => char.IsUpper(c))的时间相同吗? - peterorum
显示剩余7条评论

7

首先,你没有理由调用ToCharArray()方法,因为假设CommentText是一个字符串,它已经是一个IEnumerable<char>。其次,你应该使用char.IsUpper方法,而不是假设你只处理ASCII值。代码应该像这样:

CommentText.Count(char.IsUpper)

第三,如果您担心速度,很少有什么能比旧的for循环更好。
int count = 0;
for (int i = 0; i < CommentText.Length; i++) 
   if (char.IsUpper(CommentText[i]) count++;

一般来说,调用任何方法都比内联代码慢,但这种优化只应在您绝对确定这是代码的瓶颈时进行。


兄弟,"there is much" 应该改成 "there isn't much" 吗? - Binary Worrier

4

您只计算了标准ASCII码,而没有考虑到像ÃÐÊ等字符。

那么如何解决呢?

CommentText.ToCharArray().Where(c => Char.IsUpper(c)).Count()

谢谢 - 我在智能感知中寻找c.Upper - 没想到还有其他的。 - peterorum
不要忘记:这将计算大写字母的数量,而不考虑单词数量。 - PeterCo

4

我甚至没有测试,但我会说

int count = 0;
foreach (char c in commentText)
{
    if (Char.IsUpper(c))
        count++;
}

现在关闭了,测试看看是否更快。


没错,这个速度和我的“for”循环差不多(甚至可能稍微快一点)。 - Matt Hamilton
没有测试它,因为Matt Hamilton很体贴地替我做了这件事 :) - Binary Worrier
是的,这几乎比“for”循环慢了一半。我也不知道为什么。 - user1908746

3
你所做的是创建一个包含字符的集合,然后创建一个仅包含大写字符的新集合,然后只循环该集合以找出其中有多少个大写字符。
这将表现得更好(但仍不及普通循环),因为它不会创建中间集合:
CommentText.Count(c => Char.IsUpper(c))

编辑:根据Matt的建议,也删除了ToCharArray调用。


将谓词移入Count中,加1。同时去掉ToCharArray,速度会大大提升。 - Matt Hamilton
好的观点。我以前做过类似的事情,但在这种情况下不需要 ToCharArray。 :) - Guffa

2

I've got this

Regex x = new Regex("[A-Z]{1}", 
  RegexOptions.Compiled | RegexOptions.CultureInvariant);
int c = x.Matches(s).Count;

但我不知道它是否特别快。它也不能获取特殊字符,我想

编辑:

与此问题答案的快速比较。在vshost中进行调试,使用字符串进行10,000次迭代:
aBcDeFGHi1287jKK6437628asghwHllmTbynerA

  • 答案:20-30毫秒
  • 正则表达式解决方案:140-170毫秒

谢谢你的比较 - 我想知道正则表达式会如何表现。 - peterorum
你可以将这个代码压缩成一行:Regex.Matches(s, "[A-Z]{1}", RegexOptions.Compiled | RegexOptions.CultureInvariant).Count; - Mike Christian

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