Sum of one after another sequence
在这个场景中,我必须在集合中添加数字。一个例子就是最好的例子。
我的数据库中有这些值:
1 2 3 4 5
| | Foo |
| 1 |
| 5 |
| 8 |
| 4 | |
结果:
1 2 3 4 5
| | Foo | Result |
| 1 | 1 |
| 5 | 6 |
| 8 | 14 |
| 4 | 18 | |
如你所见,它有点斐波那契效应,但这里的扭曲度是给定的数字。
我可以在for loop的帮助下实现这一结果,但在Linq中是否可能实现这一点。比如查询数据库然后得到上面这样的结果?
任何帮助都将不胜感激。谢谢!
- 所以您想要运行总计,这是内存中的集合还是数据库查询?
- 对。运行总计。谢谢你的学期。很难说出它的名字。要回答您的问题,请使用数据库查询。我想用LINQ查询这个。
- 您的数据库是SQL吗?另外,(@servy),是否可以用SQL查询来实现这一点(运行总数的服务器端计算)?如果没有,您的问题将得到答复。
- 对。我的数据库是SQL。但在下面的答案中,有一个是你发布的。我可以在linq中声明acc变量吗?嗯,答案是肯定的。但结果查询将是不同的tho。
- @Boypasmo提供的所有答案都不能被查询提供程序转换成SQL。我相当有信心,这将是不可能与任何LINQ供应商。如果它可以在SQL中完成,就需要使用使用光标等的存储过程来完成。
- 非常感谢你抽出时间来。我该怎么处理我的问题?我应该用几乎相同的解决方案标记答案吗?你的建议是什么?供他人参考。
- @博伊斯莫,这是你的决定。
我不确定您对数据库的接触有多准确,但这里有一个解决方案可能可以改进:
1 2
| 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的项目并求和。
- 你好。谢谢。这将是一个踏脚石。但是,你能帮我理解你做了什么吗?您没有使用n参数?
- 当然,我添加了一些信息
- 我认为使用.Take会更干净一点(而不是.Where (index stuff))。
- 问题:询问数据库O(n&178;)次。
- 正确的。我不是LINQ专家,我认为有人会提高我的效率,正如我所指出的。
- @实际上,如果这是ef或linq to sql,它应该只创建一个sql查询。不过,它在对象链接的O(n&178;)中运行。
- 如果你的数组长度是奇数,你将做同样的迭代1,再做一次迭代。
- @Juharr这个Where的过载在ef中不受支持,它会崩溃。而在linq to对象中,仍然是非常可怕的实现。它不断地重复计算相同的值。
- @Servy没有意识到它不受支持,但我肯定知道它不会称为db n&178;次。
- @Juharr如果numbers是一个IQueryable,被强制转换到IEnumerable,那么它将查询数据库n^2次。如果有人在尝试实现这个解决方案时不小心(或者不理解Linq的一些复杂问题),他们很可能会这样做。
morelinq有一个Scan方法,它允许您在生成每个中间值的同时按顺序聚合值,而不仅仅是最终值,这正是您要做的。
这样你就可以写:
1
| var query = data.Scan((sum, next) => sum + next); |
您在这里需要的一个重载将复制到下面。有关详细信息和其他重载,请参见上面的链接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 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 ;
}
} |
- 当然,这也不能转换为数据库查询,但它将顺利地在内存中处理从iQueryable获得的结果(至少,通过Entity Framework和Linq to SQL,它可以)。所以我认为这是手术能得到的最好的结果(特别是与其他答案相比)。
- 为什么它抛出空源?它不能只返回一个空的IEnumerable吗?这是一种奇怪的行为…
- @这是一个决定,两者都是合理的立场。因为我没有写它,所以我无法解释为什么他们选择使用这个实现。当然,当你自己使用它的时候,你可以自由地去适应它(我可能会自己做出改变)。
我认为你可以通过以下方式实现这一目标:
1 2 3 4 5 6
| var acc = 0;
var result = numbers.Select(i =>
{
acc += i;
return acc;
}).ToList(); |
您需要ToList确保它只运行一次(否则acc将继续增长)。
另外,我不确定是否可以将其转换为查询(并在服务器端执行)。
托马斯·列夫斯基(ThomasLevesque)对一个类似的问题发表了回应,他提出了一个SelectAggregate方法,该方法提供了一个聚合计算的中间值。
在默认情况下,这个特性似乎不存在于Linq中,所以您可能无法使用Linq执行计算服务器端。
这只是对@jonesy答案的改编:
1 2
| int[] ints = new[] {1, 5, 8, 4};
var result = ints .Select((x, y ) => x + ints .Take(y ).Sum()); |
- 它和那个答案有着所有相同的问题,也就是说它不能被转换成数据库查询,而且由于它不断地重复计算相同的值,效率非常低。
- @服务是对的,但问题不是:这是否能变得超级有效?那是:林肯能做到吗?
- @否则他会加上x,所以不是。如果他把那东西拿走了,情况就是这样。
- @Stefankmitph,所以你不在乎这是一个糟糕的实现,它肯定不会以任何理由被使用?很抱歉,但我们不需要在问题中提出一个答案,因为这个答案不仅在问题的实现上很糟糕。
- @好的,太可怕了…够公平的,伙计。但它起作用了…但我该怎么办?我应该删除我的答案吗?如果是这样的话,告诉我。
- 在我看来,这个答案根本没用,所以我想把它删掉,是的。答案有效并不意味着答案是有用的。一个有效的答案,但会给用户带来重大问题,通常比没有解决方案更有害。考虑到其他解决方案并不那么糟糕,这甚至不是需要做出的选择。
- 好吧,接受琼斯的回答。他在所有答案中得到最多的赞成票(我也反对)。他的执行情况更糟(在我看来)。他还应该删除他的答案吗?(不,我不是说他应该)
- 是的,是的。作为一个答案,它是非常有害的。它因为如此糟糕的解决方案而获得如此多的赞成票,这是非常不幸的。一些可怜的灵魂最终可能会使用它。
你可以做以下的
1 2 3 4 5 6
| int runningTotal = 0;
var runningTotals = numbers .Select(n => new
{
Number = n,
RunningTotal = (runningTotal += n )
}); |
这将给你数字和运行总数。
- 你好。我可以在LINQ中使用runningTotal吗?
- 不,你不能。而且在LINQ扩展方法中引起副作用被认为是不好的做法。