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

发布于 2024-08-30 00:26:23 字数 460 浏览 3 评论 0原文

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

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 合并到一个查询中?

谢谢

I have a list of elements and want to takeWhile the sum (or any aggregation of the elements) satisfy a certain condition. The following code does the job, but i am pretty sure this is not an unusual problem for which a proper pattern should exist.

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;

Does somebody know how to solve the task in nicer way, probably combining TakeWhile and Aggregate into one query?

Thx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

囚我心虐我身 2024-09-06 00:26:23

在我看来,您想要类似 Reactive Extensions(System.Interactive 部分) - 它类似于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 有一个 类似运算符,顺便说一句 - 但目前它不支持累加器的想法输入序列不是同一类型。)

It seems to me that you want something like the Scan method from Reactive Extensions (the System.Interactive part) - it's like Aggregate, but yields a sequence instead of a single result. You could then do:

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 has a similar operator, btw - but currently it doesn't support the idea of the accumulator and input sequence not being the same type.)

十年九夏 2024-09-06 00:26:23

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

用法:

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;
            }
        }
    }
}

I recently solved a similar task and decided to create a separate extension method to avoid third-party libraries:

Usage:

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));

Output: 1, 2, 3

Extension method:

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;
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文