更新 - 对于一个有思想的心态,你可以假设Aggregate仍会产生正常的结果,无论函数传递给它,包括在优化的情况下.
我编写了这个程序来构建一个从逗号分隔的0到19999之间的长整数字符串.
using System; using System.Linq; using System.Diagnostics; namespace ConsoleApplication5 { class Program { static void Main(string[] args) { const int size = 20000; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Enumerable.Range(0, size).Select(n => n.ToString()).Aggregate((a, b) => a + ", " + b); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds + "ms"); } } }
当我运行它时,它说:
5116ms
超过五秒钟,太可怕了.当然这是因为每次循环都会复制整个字符串.
但是,如果评论中指出了一个非常小的变化呢?
using System; using System.Linq; using System.Diagnostics; namespace ConsoleApplication5 { using MakeAggregateGoFaster; // <---- inserted this class Program { static void Main(string[] args) { const int size = 20000; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Enumerable.Range(0, size).Select(n => n.ToString()).Aggregate((a, b) => a + ", " + b); stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds + "ms"); } } }
现在,当我运行它时,它说:
42ms
超过100倍.
MakeAggregateGoFaster命名空间中有什么?
更新2: 在这里写下我的答案.
为什么不使用其他形式的Aggregate?
Enumerable.Range(0, size ).Aggregate(new StringBuilder(), (a, b) => a.Append(", " + b.ToString()), (a) => a.Remove(0,2).ToString());
您可以为种子指定任何类型,在第一个lambda函数中执行所需的任何格式化或自定义调用,然后在第二个lambda函数中自定义输出类型.内置功能已经提供了您所需的灵活性.我的跑步从1444ms到6ms.
您在命名空间MakeAggregateGoFaster中使用自己的扩展方法"覆盖"System.Linq.Aggregate.
也许专门研究IEnumerable
和使用StringBuilder?
也许采用一个Expression
而不是Func
它可以分析表达式树并编译一些使用StringBuilder而不是直接调用函数的代码?
只是猜测.
没有回答这个问题,但我认为这里的标准模式是使用StringBuilder或string.Join:
string.join(", ",Enumerable.Range(0, size).Select(n => n.ToString()).ToArray())