Linq TakeWhile 取决于元素的总和(或聚合)

问题描述 投票:0回答:2

我有一个元素列表,想要取总和(或元素的任何聚合)满足某个条件。下面的代码完成了这项工作,但我很确定这不是一个不寻常的问题,应该存在适当的模式。

var list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
int tmp = 0;
var listWithSum = from x in list
                  let sum = tmp+=x
                  select new {x, sum};
int MAX = 10;
var result = from x in listWithSum
             where x.sum < MAX
             select x.x;

有人知道如何以更好的方式解决任务,可能将 TakeWhile 和 Aggregate 合并到一个查询中吗?

谢谢

c# linq aggregate
2个回答
2
投票

在我看来,您想要类似

Reactive Extensions
(System.Interactive 部分)中的 Scan 方法 - 它类似于
Aggregate
,但会产生一个序列而不是单个结果。然后你可以这样做:

var listWithSum = list.Scan(new { Value = 0, Sum = 0 },
         (current, next) => new { Value = next,
                                  Sum = current.Sum + next });

var result = listWithSum.TakeWhile(x => x.Sum < MaxTotal)
                        .Select(x => x.Value);

MoreLINQ有一个类似的运算符,顺便说一句 - 但目前它不支持累加器和输入序列不是同一类型的想法。)


0
投票

我最近解决了一个类似的任务,并决定创建一个单独的扩展方法来避免第三方库:

用途:

var list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
const int max = 10;

var result = list.TakeWhileAggregate(seed: 0, (accumulator, current) =>
{
    accumulator += current;

    return
    (
        accumulator: accumulator,
        transformedElement: current,
        proceed: accumulator < max
    );
});

Console.WriteLine(string.Join(", ", result));

输出: 1, 2, 3

扩展方法:

public static class EnumerableExtensions
{
    public static IEnumerable<TDest> TakeWhileAggregate<TSource, TAccumulate, TDest>(this IEnumerable<TSource>? source, TAccumulate seed, Func<TAccumulate, TSource, (TAccumulate accumulator, TDest transformedElement, bool proceed)>? func)
    {
        ArgumentNullException.ThrowIfNull(source);
        ArgumentNullException.ThrowIfNull(func);

        var accumulator = seed;
        foreach (var element in source)
        {
            (accumulator, var transformedElement, var proceed) = func(accumulator, element);
            if (proceed)
            {
                yield return transformedElement;
            }
            else
            {
                break;
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.