LINQ - 聚合并计算几个参数

时间:2013-12-01 20:32:23

标签: c# linq object

我有以下

List<Stock> _investments= new List<Stock>()
        {
            new Stock {id=msft, price =12, qty=20}
            new Stock {id=msft, price =53, qty=50}
            new Stock {id=csco, price =222, qty=20}
            new Stock {id=fb, price 40, qty=100}
        }

如果有一个符号,比如msft,我想获得总投资和收费价格。 在上面的例子中,它将是

id=msft, qty=70, price = (12*20 + 53 *50)/70 = 41.29

如何在LINQ中执行此操作? 我可以这样得到12 * 20 + 53 * 50:

var c = _investments.Where(i => i.ID == investmentName.ToUpper()).Sum(k => k.InitialPrice * k.Qty);

但如何以高效的方式包含总数量

3 个答案:

答案 0 :(得分:2)

使用GroupBySum

var result = _investments
   .Where(g => g.Key == "msft")
   .GroupBy(i => i.id)
   .Select(g => new{ id = g.Key,  qty = g.Sum(i => i.qty), grp = g })
   .Select(x => new
   {
       x.id,
       x.qty,
       price = Math.Round(x.grp.Sum(i => (decimal)i.price * i.qty) / x.qty, 2)
   });

Demonstration

请注意,我已将价格转换为decimal以防止整数除法(截断小数位)。 Math.Round用于将结果舍入两位小数。

答案 1 :(得分:2)

最简单的方法似乎是:

var relevantInvestments = _investments
    .Where(i => i.ID == investmentName.ToUpper())
    .ToArray();

var totalQty = relevantInvestments.Sum(k => k.Qty);
var c = relevantInvestments.Sum(k => k.InitialPrice * k.Qty) / totalQty;

只迭代一次:

var c = _investments
    .Where(i => i.ID == investmentName.ToUpper())
    .Aggregate(
        new { Price = 0, TotalQty = 0 },
        (total, i) => new 
                      { 
                          Price = total.Price + i.InitialPrice * i.Qty,
                          TotalQty = total.TotalQty + i.Qty
                      },
        i => i.Price / i.TotalQty);

答案 2 :(得分:2)

包含计算值的好方法可能是为此创建一个类。这样,您可以在不使用匿名类型的情况下清楚地命名和键入值,并确保计算它的工作只发生一次。为简单起见,我在这里到处使用double,并且string用于ID,这些ID可能与您的类型匹配,也可能不匹配(decimal应该用于金额)。

class StockGroup
{
    public List<Stock> Stocks { get; private set; }

    public string Id { get; private set; }
    public double TotalPrice { get; private set; }
    public double AveragePrice { get; private set; }
    public double Qty { get; private set; }

    public StockGroup(string id, IEnumerable<Stock> stocks)
    {
        this.Id = id;
        this.Stocks = stocks.ToList();
        foreach (var stock in this.Stocks)
        {
            this.Qty += stock.Qty;
            this.TotalPrice += stock.Price * stock.Qty;
        }
        this.AveragePrice = this.TotalPrice / this.Qty;
    }
}

// use like
var groups =
         _investments.GroupBy(x => x.Id).Select(x => new StockGroup(x.Key, x));