优化字符串连接的聚合

Dan*_*ker 18 c# optimization linq-to-objects

更新 - 对于一个有思想的心态,你可以假设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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,它说:

5116ms
Run Code Online (Sandbox Code Playgroud)

超过五秒钟,太可怕了.当然这是因为每次循环都会复制整个字符串.

但是,如果评论中指出了一个非常小的变化呢?

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我运行它时,它说:

42ms
Run Code Online (Sandbox Code Playgroud)

超过100倍.

MakeAggregateGoFaster命名空间中有什么?

更新2: 在这里写下我的答案.

小智 44

为什么不使用其他形式的Aggregate?

Enumerable.Range(0, size ).Aggregate(new StringBuilder(),
        (a, b) => a.Append(", " + b.ToString()),
        (a) => a.Remove(0,2).ToString());
Run Code Online (Sandbox Code Playgroud)

您可以为种子指定任何类型,在第一个lambda函数中执行所需的任何格式化或自定义调用,然后在第二个lambda函数中自定义输出类型.内置功能已经提供了您所需的灵活性.我的跑步从1444ms到6ms.


mac*_*nir 15

您在命名空间MakeAggregateGoFaster中使用自己的扩展方法"覆盖"System.Linq.Aggregate.

也许专门研究IEnumerable<string>和使用StringBuilder?

也许采用一个Expression<Func<string, string, string>>而不是Func<string, string, string>它可以分析表达式树并编译一些使用StringBuilder而不是直接调用函数的代码?

只是猜测.


Jim*_*mmy 5

没有回答这个问题,但我认为这里的标准模式是使用StringBuilder或string.Join:

string.join(", ",Enumerable.Range(0, size).Select(n => n.ToString()).ToArray())
Run Code Online (Sandbox Code Playgroud)


Jim*_*mmy 5

我之所以问这是否是一个谜题,是因为只要满足所陈述问题的字面意义,谜题就可以不同程度地牺牲鲁棒性。考虑到这一点,这里是:

解决方案 1(立即运行,问题未验证):

public static string Aggregate(this IEnumerable<string> l, Func<string, string, string> f) {
     return "";
}
Run Code Online (Sandbox Code Playgroud)

解决方案 2(运行速度与问题所需的速度差不多,但完全忽略委托):

public static string Aggregate(this IEnumerable<string> l, Func<string, string, string> f) {
    StringBuilder sb = new StringBuilder();
    foreach (string item in l)
        sb.Append(", ").Append(item);
    return sb.Remove(0,2).ToString();
}
Run Code Online (Sandbox Code Playgroud)