假设我有一个inifite生成器A()
。我想要的是获取A
返回的所有数字的总和,使得总和在一个LINQ表达式中不超过值N
。
我想知道是否有一种扩展方法可以帮助我吗?
经典的方式是:
int sum = 0;
foreach (int x in A()) {
sum += x;
if (sum > N) {
break;
}
}
return sum;
但是我一直在考虑如何只在一个表达中做到这一点而没有成功......
答案 0 :(得分:3)
如果A
是无限生成器,则只能使用内置的LINQ方法在单个语句中执行此操作。
要在一个语句中干净利落地完成任务,没有任何副作用,您可能需要使用某种Scan
方法来计算输入序列的prefix sum。然后你只需要大于N
的第一个元素。简单!
int sum = A().Scan((s, x) => s + x).First(s => s > N);
// ...
public static class EnumerableExtensions
{
public static IEnumerable<T> Scan<T>(
this IEnumerable<T> source, Func<T, T, T> func)
{
if (source == null) throw new ArgumentNullException("source");
if (func == null) throw new ArgumentNullException("func");
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
T accumulator = e.Current;
yield return accumulator;
while (e.MoveNext())
{
accumulator = func(accumulator, e.Current);
yield return accumulator;
}
}
}
}
}
答案 1 :(得分:3)
使用标准惯用语LINQ,这是不可能的。您需要的语义是Aggregate()
和TakeWhile()
的组合。否则,你需要有副作用,这在LINQ中是禁止的。
以下是使用副作用的一种方法示例:
var temp = 0;
var sum = A().TakeWhile(i =>
{
var res = !(temp > N);
temp += i;
return res;
}).Sum();
答案 2 :(得分:3)
当然有一种方法可以使用单个LINQ表达式来完成此操作。最简单的我可以提出并仍然有一些普遍性和优雅是:
public static int SumWhile(this IEnumerable<int> collection, Func<int, bool> condition)
{
int sum = 0;
foreach (int i in collection)
{
sum += i;
if (!condition(sum))
break;
}
return sum;
}
可以被称为:
int sum = A().SumWhile(i => i <= N);
是的,只需一个LINQ表达式!玩得开心
答案 3 :(得分:1)
可能最接近你最初的想法:
int sum = 0;
int limit = 500;
A().TakeWhile(i => (sum += i) < limit).Count();
//Now the variable named sum contains the smaller sum of elements being >= limit
Count()不用于返回值,而是强制实际枚举。
答案 4 :(得分:0)
让我们看看我的要求是否正确。
A()是无限生成器。根据定义,它会永远生成值(在本例中为整数)。
您希望查找小于N的所有值,并将它们一起添加。
Linq不是问题。
,在A()完成生成之前,你不会完成添加。 顺便说一句,你发布的代码并不是所有的值都小于N ......它会将所有值相加,直到找到小于N的值,然后退出查找。那是你的意思吗?答案 5 :(得分:0)
我相信下面的可怕代码可以满足您的要求。 : - )
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication12 {
public class Program {
public static void Main(string[] args) {
const int N=100;
int sum;
try {
sum=A().Aggregate((self, next) => {
if(self+next<=N)
return self+next;
else
throw new ResultException(self);
});
} catch(ResultException re) {
sum=re.Value;
}
Debug.Print("Sum="+sum);
}
private class ResultException : Exception {
public readonly int Value;
public ResultException(int value) {
Value=value;
}
}
private static IEnumerable<int> A() {
var i=0;
while(true) {
yield return i++;
}
}
}
}
答案 6 :(得分:-1)
int sum = A()。其中(x =&gt; x&lt; N).Sum();