LINQ 对项集合求和以返回包含结果的对象(多列)



我知道我可以用 foreach 做下面的事情,但想知道是否有一种干净、"性感"的方式来用 LINQ 做到这一点。

public class item
{
    public int total { get; set; }
    public int net { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        List<item> items = new List<item>()
                               {
                                   new item() { total = 123, net = 423},
                                   new item() { total = 432, net = 54},
                                   new item() { total = 33, net = 57654},
                                   new item() { total = 33, net = 423},
                                   new item() { total = 3344, net = 423},
                                   new item() { total = 123, net = 423},
                                   new item() { total = 123, net = 98},
                                   new item() { total = 123, net = 867},
                                   new item() { total = 123, net = 876},
                                   new item() { total = 123, net = 423},
                                   new item() { total = 123, net = 543},
                                   new item() { total = 543, net = 345},
                               };
        item i = new item();
        foreach (var item in items)
        {
            i.net += item.net;
            i.total += item.total;
        }
    }
}

我想做的是,对于给定的对象列表,对每一列/字段求和,并返回一个带有每个值总和的对象。

我试过了:

var result = (from e in items
                     select new
                                {
                                    NET_GRAND = e.net,
                                    TOTAL_GRAND = e.total
                                }).ToList();

以及下面的变化,但没有运气:

 var result = (from t in items
                     group t by new {t.net, t.total}
                     into grp
                     select new
                                {
                                    NET_GRAND = grp.Sum(t => t.net),
                                    TOTAL_GRAND = grp.Sum(t => t.total)
                                }).GroupBy(x => new { x.NET_GRAND, x.TOTAL_GRAND }).ToList();

编辑

应该指出,效率在这里很重要,性感也很重要。

如果你不关心迭代列表两次,

var i = new item
    { 
        net = items.Sum(it => it.net), 
        total = items.Sum(it => it.total) 
    };

如果您确实关心将列表迭代两次(就像您为未知来源的IEnumerable执行此操作一样(,

var i = items.Aggregate(new item(), 
    (accumulator, it) => 
        new item 
        {
            net = accumulator.net + it.net, 
            total = accumulator.total + it.total 
        } 
);

看起来你真的很想要:

var result = new {
    NetGrand = items.Sum(t => t.net),
    TotalGrand = items.Sum(t => t.total)
};

另一方面,我可能只是将它们分成两个不同的局部变量:

var netGrand = items.Sum(t => t.net);
var totalGrand = items.Sum(t => t.total);

当然,这会重复列表两次,但在大多数情况下,我希望这不会引起注意。

item totals = new item 
              { 
                 net = items.Sum(i => i.net),
                 total = items.Sum(i => i.total)  
              };

但请记住,此查询将枚举一个列表两次,因此对于大型列表,这不会像旧的好的单foreach循环那样有效。

var item = new item();
item.net = items .Sum(x=>x.net);
item.total = items.Sum(x=>x.total);

使用 foreach 循环。 你说你关心效率,即使你不是,也没有理由使用 Linq 编写它只是为了使用 Linq。

当我们获得更多的程序经验时,我们发现的一件事是,仅仅因为某些事情是"旧方式"完成的,并不能使它变得糟糕。 并且转换为新的 wiz-bang 方法并不能使它变得更好。 事实上,如果你的代码以旧的方式工作,"升级"是注入缺陷的原因,在许多情况下没有任何优势。

充其量,此 Linq 方法的计算时间将延长 2 倍。

var i = new item
    { 
        net = items.Sum(it => it.net), 
        total = items.Sum(it => it.total) 
    };

不确定聚合方法,但显然需要更长的时间。

我相信

您可以使用 LINQ 完成此操作,而无需通过将 GroupBy 与键的常量值一起使用(在本例中我使用 1(进行两次迭代。

item totals = items.GroupBy(i => 1).Select(g => new item()
{
    net = g.Sum(i => i.net),
    total = g.Sum(i => i.total)
}).Single();

最新更新