我有这个场景,我必须在集合中添加数字。一个例子就是最好的例子。
我在我的数据库中有这些值:
| Foo |
| 1 |
| 5 |
| 8 |
| 4 |
结果:
| Foo | Result |
| 1 | 1 |
| 5 | 6 |
| 8 | 14 |
| 4 | 18 |
正如你所看到的,它有一点斐波那契效应,但这里的扭曲是数字给出。
我可以在for loop
的帮助下实现这一结果,但这可以在Linq
中完成。就像查询数据库然后得到如上所示的结果?
非常感谢任何帮助。谢谢!
答案 0 :(得分:4)
我不确定您是如何接触数据库的,但这是一个可以改进的解决方案:
var numbers = new List<int> { 1, 5, 8, 4 };
var result = numbers.Select((n, i) => numbers.Where((nn, ii) => ii <= i).Sum());
Select
和Where
的这个重载获取对象(每个数字)和该对象的索引。对于每个索引,我使用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());