【问题标题】:LINQ Aggregate function up to current rowLINQ 聚合函数到当前行
【发布时间】:2014-07-13 08:55:05
【问题描述】:

假设我有以下内容

var list = new []{
            new { Price = 1000, IsFirst = true}, 
            new { Price = 1100, IsFirst = false},
            new { Price = 450, IsFirst = true},
            new { Price = 300, IsFirst = false}
};

我想生成以下输出:

Price  IsFirst  First Second Final
----------------------------------
1000   True     1000  0      1000
1100   False    0     1100   -100
450    True     450   0      350
300    False    0     300    50

是否可以将某种聚合函数处理到当前行?我喜欢将所有东西都放在纯 LINQ 中,但到目前为止,我别无选择,只能手动迭代列表并有条件地对列求和。

var result = list.Select(x => new 
{
    Price = x.Price,
    IsFirst = x.IsFirst,
    First = x.IsFirst ? x.Price : 0,
    Second = !x.IsFirst ? x.Price : 0,
    Final = 0 // ???
}).ToList();

int sum = 0;

for(int i=0; i<result.Count(); i++)
{
    sum += (result[i].IsFirst ? result[i].Price : - result[i].Price);   
    // updating Final value manually
}

【问题讨论】:

标签: c# linq


【解决方案1】:

最简单的方法是使用 Microsoft 响应式扩展团队的“交互式扩展”方法Scan。 (使用 NuGet 并查找 Ix-Main。)

var query =
    list
        .Scan(new
        {
            Price = 0,
            IsFirst = true,
            First = 0,
            Second = 0,
            Final = 0
        }, (a, x) => new
        {
            Price = x.Price,
            IsFirst = x.IsFirst,
            First = x.IsFirst ? x.Price : 0,
            Second = !x.IsFirst ? x.Price : 0,
            Final = a.Final + (x.IsFirst ? x.Price : - x.Price)
        });

这给出了:

但是,您可以使用内置的 Aggregate 操作符,如下所示:

var query =
    list
        .Aggregate(new []
        {
            new
                {
                    Price = 0,
                    IsFirst = true,
                    First = 0,
                    Second = 0,
                    Final = 0
                }
        }.ToList(), (a, x) =>
        {
            a.Add(new
            {
                Price = x.Price,
                IsFirst = x.IsFirst,
                First = x.IsFirst ? x.Price : 0,
                Second = !x.IsFirst ? x.Price : 0,
                Final = a.Last().Final + (x.IsFirst ? x.Price : - x.Price)
            });
            return a;
        })
        .Skip(1);

你会得到同样的结果。

【讨论】:

    【解决方案2】:

    您想要的称为运行总计

    据我所知,在 LINQ 中没有内置的方法可以做到这一点,但是很多人已经编写了扩展方法来做到这一点。我在网上很快找到的一个是这个:

    基于此,将您的代码转换为扩展方法应该相当容易

    • 遇到带有IsFirst = true的项目时重置中间值,
    • 否则会递减值,
    • 并产生它。

    【讨论】:

      【解决方案3】:

      你可以这样做:

      int final = 0;
      var result = list.Select(x => new
      {
          Price = x.Price,
          IsFirst = x.IsFirst,
          First = x.IsFirst ? x.Price : 0,
          Second = !x.IsFirst ? x.Price : 0,
          Final = x.IsFirst ? final+=x.Price : final-=x.Price
      }).ToList();
      

      但是您需要在 linq 表达式之外定义一个整数(final)来跟踪总和。

      【讨论】:

        猜你喜欢
        • 2021-10-30
        • 1970-01-01
        • 2011-04-08
        • 2012-11-02
        • 1970-01-01
        • 1970-01-01
        • 2020-05-15
        • 2020-03-12
        • 1970-01-01
        相关资源
        最近更新 更多