一个接一个序列的总和

时间:2015-04-02 13:38:34

标签: c# linq

我有这个场景,我必须在集合中添加数字。一个例子就是最好的例子。

我在我的数据库中有这些值:

| Foo |
| 1   |
| 5   |
| 8   |
| 4   |

结果:

| Foo | Result |
|  1  | 1      |
|  5  | 6      |
|  8  | 14     |
|  4  | 18     |

正如你所看到的,它有一点斐波那契效应,但这里的扭曲是数字给出。

我可以在for loop的帮助下实现这一结果,但这可以在Linq中完成。就像查询数据库然后得到如上所示的结果?

非常感谢任何帮助。谢谢!

5 个答案:

答案 0 :(得分:4)

我不确定您是如何接触数据库的,但这是一个可以改进的解决方案:

var numbers = new List<int> { 1, 5, 8, 4 };
var result = numbers.Select((n, i) => numbers.Where((nn, ii) => ii <= i).Sum());

SelectWhere的这个重载获取对象(每个数字)和该对象的索引。对于每个索引,我使用numbers.Where对具有较低和相等索引的所有项进行求和。

例如,当Select到达数字8(索引2)时,numbers.Where会抓取索引为0-2的项目并对它们求和。

答案 1 :(得分:3)

我认为你可以通过以下方式实现这一目标:

var acc = 0;
var result = numbers.Select(i =>
    {
        acc += i;
        return acc;
    }).ToList();

您需要ToList确保它只会运行一次(否则acc会继续增长。)

此外,我不确定它是否可以转换为查询(并执行服务器端)。

Thomas Levesque发布了对类似问题的回复,其中提供了SelectAggregate方法,该方法提供了聚合计算的中间值。

默认情况下,Linq中不存在此功能,因此您可能无法使用Linq执行计算服务器端。

答案 2 :(得分:3)

MoreLINQ has a Scan method允许您聚合序列中的值,同时产生每个中间值,而不仅仅是最终值,这正是您尝试做的事情。

你可以这样写:

var query = data.Scan((sum, next) => sum + next);

您需要的一个重载将在下面复制。有关详细信息和其他重载,请参阅上面的链接:

    public static IEnumerable<TSource> Scan<TSource>(this IEnumerable<TSource> source,
        Func<TSource, TSource, TSource> transformation)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (transformation == null) throw new ArgumentNullException("transformation");
        return ScanImpl(source, transformation);
    }

    private static IEnumerable<T> ScanImpl<T>(IEnumerable<T> source, Func<T, T, T> f)
    {
        using (var i = source.GetEnumerator())
        {
            if (!i.MoveNext())
                throw new InvalidOperationException("Sequence contains no elements.");

            var aggregator = i.Current;

            while (i.MoveNext())
            {
                yield return aggregator;
                aggregator = f(aggregator, i.Current);
            }
            yield return aggregator;
        }
    }

答案 3 :(得分:2)

您可以执行以下操作

int runningTotal = 0;
var runningTotals = numbers.Select(n => new 
    { 
        Number = n, 
        RunningTotal = (runningTotal += n)
    });

这将为您提供号码和运行总数。

答案 4 :(得分:2)

只是改编了@ Jonesy的答案:

int[] ints = new[] {1, 5, 8, 4};
var result = ints.Select((x, y) => x + ints.Take(y).Sum());