【问题标题】:How can I get running totals of integer values from a List()?如何从 List() 中获取整数值的运行总计?
【发布时间】:2011-01-18 12:51:58
【问题描述】:

List 的对象具有如下属性:

public class PropertyDetails
{

 public int Sequence { get; set; }

 public int Length { get; set; }

 public string Type { get; set; }

 public int Index { get; set; }

}

列表将具有排序的序列。

List 的对象值如下:

序列= 1 长度=20 类型="" 索引=0

序列= 2 长度=8 类型="" 索引=0

序列= 3 长度=6 类型="" 索引=0

序列= 4 长度=20 类型="" 索引=0

序列= 5 长度=8 类型="" 索引=0

我想要 Linq 查询,它会给我结果列表为

序列= 1 长度=20Type="" 索引=20

序列= 2 长度=8 类型="" 索引=28

序列= 3 长度=6 类型="" 索引=34

序列= 4 长度=20 类型="" 索引=54

序列= 5 长度=8 类型="" 索引=62

其中 index 是考虑序列的 Length 的累积总和。

【问题讨论】:

    标签: c# linq list sorting


    【解决方案1】:

    我从没想过我会这么说,但我发现 Jon 的解决方案过于工程化。相反,我发现 LINQ 是解决这个问题的错误解决方案。您想要操纵状态,不适合传统的 LINQ 运算符。

    我会这样做:

    var sum = 0;
    foreach (var p in list) {
      sum += p.Length;
      p.Index = sum;
    }
    

    LINQ 是一把锤子。确保使用正确的工具来解决问题,而不是仅仅寻求锤击建议。

    【讨论】:

    • 假设 OP 想要操纵状态。如果是这样,那么这是正确的方法。如果不是不是,那么这根本不合适。你说得对,LINQ 根本不适合你想要改变现有对象的情况。这是一个很好的解决方案,但您需要一种更实用的方法。很遗憾,我们没有足够的信息来了解 OP 试图做什么。
    【解决方案2】:

    没有标准的 LINQ 运算符可以执行此操作 - 基本上您需要一个正在运行的聚合。你现在可以用带有副作用的查询来伪造它,但就是这样。

    幸运的是,编写自己的查询运算符来执行此操作很容易。比如:

    public static IEnumerable<TResult> Scan<TSource, TResult>(
        this IEnumerable<TSource> source,
        TResult seed,
        Func<TResult, TSource, TResult> func)
    {
        TResult current = seed;
        // TODO: Argument validation
        foreach (TSource item in source)
        {
            current = func(current, item);
            yield return current;
        }
    }
    

    那么你可以使用:

    var query = list.Scan(new PropertyDetails(),
                          (current, item) => new PropertyDetails { 
                               Sequence = item.Sequence,
                               Length = item.Length,
                               Index = current.Index + item.Length
                          });
    

    编辑:我没有检查细节,但我相信 Reactive Extensions 在其 System.Interactive 程序集中有类似的方法。

    【讨论】:

    • 我真的不明白这个的用途。数据库将无法有效地处理它,对吧?如果是针对“对象的 LINQ”,那么我的问题就是“为什么”?实现一个新的扩展方法,为列表中的每个元素创建新对象,除此之外,仍然需要编写比使用简单的 for 循环更多的代码。 LINQ 不适合这个。
    • @Jakob:在很多情况下运行聚合很有用。前几天我也想要一个。我喜欢能够以声明的方式表达这种聚合,而不是编写一个 foreach 循环。我还希望能够将它用作更大查询的一部分。
    • 虽然我同意您的推理,即拥有可重复使用的通用解决方案很有用,但我认为您首先必须务实。在这种情况下,即使使用您的解决方案(即第二个代码块)也比整个 Jakob 的代码更多。他的也更容易阅读和理解。如果在多个地方使用,您更通用的解决方案会生成比复制和粘贴更多的代码行 - 我们知道错误的数量与代码行的数量成正比。
    • @Theo:这取决于 OP 是否实际上 想要改变原始对象。如果他这样做了,那么 Jakob 的解决方案更适用。如果他不这样做,那么我的更适用。使用这样的函数式方法可以使其余代码更易于推理,IMO。
    • @Theo 我必须同意@Jon 的最后一条评论。
    【解决方案3】:

    可能是这样的(不是很可读):

    var newList = list.Select(x =>
                            new PropertyDetails()
                            {
                                Type = x.Type,
                                Length = x.Length,
                                Sequence = x.Sequence,
                                Index = list.Take(x.Sequence).Select(y => y.Length).Aggregate((a, b) => a + b)
                            }
    );
    

    【讨论】:

    • 糟糕,这个时间复杂度是二次方的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 2019-02-10
    相关资源
    最近更新 更多