如何计算由LINQ中的谓词过滤的大范围的总和

时间:2015-01-08 10:12:01

标签: c# linq

我试图通过传递int.MaxValue代替1000来测试Problem 1 projecteuler.net的三种解决方案的效果。

第一个解决方案

    long sum = SumDivisibleBy(3) + SumDivisibleBy(5) - SumDivisibleBy(15);
    Console.WriteLine(sum);

SumDivisibleBy是:

public static long SumDivisibleBy(int k, int n = int.MaxValue)
{
    long m = n / k;
    return k * (m * (m + 1) / 2);
}

更快(约27秒)

第二个解决方案

    long sum = 0;
    for (int i = 0; i < int.MaxValue; i++)
    {
        if (i % 3 == 0 || i % 5 == 0)
        {
            sum += (long)i;
        }
    }
    Console.WriteLine(sum);

第三个解决方案(我认为这是一个优雅的解决方案)是:

    Console.WriteLine(Enumerable.Range(1, 999)
                                .Where(x => x % 3 == 0 || x % 5 == 0)
                                .Sum());

但我无法达到此目的(用于测试性能目的):

    Console.WriteLine(Enumerable.Range(1, int.MaxValue)
                                    .Where(x => x % 3 == 0 || x % 5 == 0)
                                    .Sum());
因为OverflowException的性质,它给了我一个int Sum(this IEnumerable<int> source)是自然的。

我的问题是:

如何在下面的代码中将int Sum(this IEnumerable<int> source)转发到long Sum(this IEnumerable<long> source)

    Console.WriteLine(Enumerable.Range(1, int.MaxValue)
                                    .Where(x => x % 3 == 0 || x % 5 == 0)
                                    .Sum());

3 个答案:

答案 0 :(得分:2)

尝试将过滤的整数序列投影到一系列long:

.Where(x => x % 3 == 0 || x % 5 == 0)
.Select(x => (long)x)
.Sum()

请注意,.Cast<long>()看起来更优雅,但won't work for this kind of conversion

答案 1 :(得分:2)

您可以扩展Enumerable类,如下所示:

public static class MyExtensions
{
    public static IEnumerable<long> Range(long start, long count)
    {
        for (long i = start; i < start + count; i++)
        {
            yield return i;
        }
    } 
}

通过这种方式,您可以使用Sum方法,而不会出现任何问题,如下所示:

MyExtensions.Range(1, int.MaxValue)
            .Where(x => x % 3 == 0 || x % 5 == 0)
            .Sum());

答案 2 :(得分:0)

仅供参考......我测试了所有推荐的解决方案(LinqPad)并检查了执行时间。

方法1)转换选择 - 时间: 1:23.360s (中)

.Select(x => (long)x)

方法2)扩展方法 - 时间: 02:06.768s (慢)

MyExtensions.Range(1, int.MaxValue)
            .Where(x => x % 3 == 0 || x % 5 == 0)
            .Sum());
方法3) T.Glatzer在对Ani解决方案的评论中提出建议 - 时间: 00:54.567 (快速)

Enumerable.Range(1, int.MaxValue).Where(x=> x%3==0 || x%5==0).Sum(x=>(long)x);

<强> 结论:
每种方法都比你的 SumDivisibleBy 函数慢得多,那么除了优雅的代码之外,Linq解决方案的好处是什么呢?没有。

注意:我没有在内存使用,CPU使用率等其他方面进行测试。