在一个LINQ查询中获取两列的总和

时间:2010-03-12 11:15:22

标签: c# .net linq linq-to-sql sum

让我说我有一张叫做的桌子 Items(ID int,Done int,Total int)

我可以通过两个查询来完成:

int total = m.Items.Sum(p=>p.Total)
int done = m.Items.Sum(p=>p.Done)

但是我想在一个查询中执行此操作,如下所示:

var x = from p in m.Items select new { Sum(p.Total), Sum(p.Done)};

当然有一种方法可以从LINQ语法调用聚合函数......?

9 个答案:

答案 0 :(得分:80)

这样可以解决问题:

from p in m.Items
group p by 1 into g
select new
{
    SumTotal = g.Sum(x => x.Total), 
    SumDone = g.Sum(x => x.Done) 
};

答案 1 :(得分:10)

要对表进行求和,请按常量分组:

from p in m.Items
group p by 1 into g
select new {
    SumTotal = g.Sum(x => x.Total),
    SumDone = g.Sum(x => x.Done)
}

答案 2 :(得分:9)

怎么样

   m.Items.Select(item => new { Total = item.Total, Done = item.Done })
          .Aggregate((t1, t2) => new { Total = t1.Total + t2.Total, Done = t1.Done + t2.Done });

答案 3 :(得分:5)

弄清楚在我的其余代码中提取总和或其他聚合的位置使我感到困惑,直到我记得我构造的变量是一个Iqueryable。假设我们的数据库中有一个由Orders组成的表,我们想为ABC公司生成一个摘要:

var myResult = from g in dbcontext.Ordertable
               group p by (p.CUSTNAME == "ABC") into q  // i.e., all of ABC company at once
               select new
{
    tempPrice = q.Sum( x => (x.PRICE ?? 0m) ),  // (?? makes sure we don't get back a nullable)
    tempQty = q.Sum( x => (x.QTY ?? 0m) )
};

现在有趣的部分 - tempPrice和tempQty未在任何地方声明,但它们必须是myResult的一部分,不是吗?按如下方式访问它们:

Console.Writeline(string.Format("You ordered {0} for a total price of {1:C}",
                                 myResult.Single().tempQty,
                                 myResult.Single().tempPrice ));

也可以使用许多其他可查询方法。

答案 4 :(得分:3)

使用帮助器元组类,您可以使用自己的or-in .NET 4 - 标准的那些:

var init = Tuple.Create(0, 0);

var res = m.Items.Aggregate(init, (t,v) => Tuple.Create(t.Item1 + v.Total, t.Item2 + v.Done));

res.Item1Total列的res.Item2列和Done的总和。

答案 5 :(得分:1)

//Calculate the total in list field values
//Use the header file: 

Using System.Linq;
int i = Total.Sum(G => G.First);

//By using LINQ to calculate the total in a list field,

var T = (from t in Total group t by Total into g select g.Sum(t => t.First)).ToList();

//Here Total is a List and First is the one of the integer field in list(Total)

答案 6 :(得分:1)

已经回答了这个问题,但是其他答案仍会对集合进行多次迭代(多次调用Sum)或者创建大量的中间对象/元组可能没问题,但如果不是,那么你可以创建一个扩展方法(或多个),以旧式方式执行,但非常适合LINQ表达式。

这样的扩展方法如下所示:

private WidgetViewComponent(IWidgetService widgetService)
{
    _WidgetService = widgetService;
}

你可以像这样使用它:

public WidgetViewComponent(IWidgetService widgetService)
{
    _WidgetService = widgetService;
}

答案 7 :(得分:0)

使用C# 7.0中引入的对元组的语言支持,您可以使用以下LINQ表达式解决此问题:

var itemSums = m.Items.Aggregate((Total: 0, Done: 0), (sums, item) => (sums.Total + item.Total, sums.Done + item.Done));

完整代码示例:

var m = new
{
    Items = new[]
    {
        new { Total = 10, Done = 1 },
        new { Total = 10, Done = 1 },
        new { Total = 10, Done = 1 },
        new { Total = 10, Done = 1 },
        new { Total = 10, Done = 1 },
    },
};

var itemSums = m.Items.Aggregate((Total: 0, Done: 0), (sums, item) => (sums.Total + item.Total, sums.Done + item.Done));

Console.WriteLine($"Sum of Total: {itemSums.Total}, Sum of Done: {itemSums.Done}");

答案 8 :(得分:-2)

当您使用分组时,Linq会创建一个新的项目集合,因此您有两个项目集合。

以下是两个问题的解决方案:

  1. 在一次迭代中总结任意数量的成员
  2. 避免重复您的项目集合
  3. 代码:

    public static class LinqExtensions
    {
      /// <summary>
      /// Computes the sum of the sequence of System.Double values that are obtained 
      /// by invoking one or more transform functions on each element of the input sequence.
      /// </summary>
      /// <param name="source">A sequence of values that are used to calculate a sum.</param>
      /// <param name="selectors">The transform functions to apply to each element.</param>    
      public static double[] SumMany<TSource>(this IEnumerable<TSource> source, params Func<TSource, double>[] selectors)
      {
        if (selectors.Length == 0)
        {
          return null;
        }
        else
        {
          double[] result = new double[selectors.Length];
    
          foreach (var item in source)
          {
            for (int i = 0; i < selectors.Length; i++)
            {
              result[i] += selectors[i](item);
            }
          }
    
          return result;
        }
      }
    
      /// <summary>
      /// Computes the sum of the sequence of System.Decimal values that are obtained 
      /// by invoking one or more transform functions on each element of the input sequence.
      /// </summary>
      /// <param name="source">A sequence of values that are used to calculate a sum.</param>
      /// <param name="selectors">The transform functions to apply to each element.</param>
      public static double?[] SumMany<TSource>(this IEnumerable<TSource> source, params Func<TSource, double?>[] selectors) 
      { 
        if (selectors.Length == 0)
        {
          return null;
        }
        else
        {
          double?[] result = new double?[selectors.Length];
    
          for (int i = 0; i < selectors.Length; i++)
          {
            result[i] = 0;
          }
    
          foreach (var item in source)
          {
            for (int i = 0; i < selectors.Length; i++)
            {
              double? value = selectors[i](item);
    
              if (value != null)
              {
                result[i] += value;
              }
            }
          }
    
          return result;
        }
      }
    }
    

    以下是你必须进行总结的方法:

    double[] result = m.Items.SumMany(p => p.Total, q => q.Done);
    

    这是一个一般的例子:

    struct MyStruct
    {
      public double x;
      public double y;
    }
    
    MyStruct[] ms = new MyStruct[2];
    
    ms[0] = new MyStruct() { x = 3, y = 5 };
    ms[1] = new MyStruct() { x = 4, y = 6 };
    
    // sum both x and y members in one iteration without duplicating the array "ms" by GROUPing it
    double[] result = ms.SumMany(a => a.x, b => b.y);
    

    你可以看到

    result[0] = 7 
    result[1] = 11