2010-03-12 5 views
48

disons que j'ai une table appelée Items (ID int, Fait int, Total int)Obtenez somme de deux colonnes dans une requête LINQ

je peux le faire par deux requêtes:

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

Mais je voudrais le faire dans une requête, quelque chose comme ceci:

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

Certes, il existe un moyen d'appeler des fonctions d'agrégation de la syntaxe LINQ ...?

Répondre

68

Cela fera l'affaire:

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) 
}; 
+7

Ou quand l'article n'a pas d'identifiant unique, vous pouvez groupe écrire 'p par p en g'. – Steven

+1

Cela a fait l'affaire, mais avec une modification: de p dans m.Articles groupe p par p.Id en g select new {SumTotal = g.Sum (r => r.Total), SumDone = g.Sum (r => r.Done)} – Axarydax

+1

Vous avez raison, 'p' était déjà utilisé dans la requête. Je l'ai réparé. – Steven

1

Avec une classe de tuple d'aide, que ce soit votre propre ou — dans .NET 4 — les standards que vous pouvez faire ceci:

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

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

Et res.Item1 est le total de la colonne Total et res.Item2 de la colonne Done .

8

Que diriez-vous

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 }); 
9

Pour résumer la table, le groupe par une constante:

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) 
} 
+0

s'il vous plaît quelqu'un peut poster une version de vb.net? – Zeus

+0

@Zeus Voici le code VB.Net, De g Dans De p Dans m.ItemsGroup p Par 1New Avec {_ \t Key .SumTotal = g.Sum (Fonction (x) x.Total), _ \t Key. SumDone = g.Sum (Fonction (x) x.Done) _ } Vous pouvez convertir les codes ici [link] (http://converter.telerik.com/) –

+0

@Sibeesh, merci pour l'aide – Zeus

5

déterminer où extraire les sommes ou autre agrégat dans le reste de mon code m'a confondu, jusqu'à ce que je me suis souvenu que la variable que j'ai construite était un Iqueryable. Supposons que nous ayons une table dans notre base de données composée de commandes, et nous voulons produire un résumé de la société 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)) 
}; 

Maintenant, la partie amusante - tempPrice et tempQty ne sont pas déclarés nulle part, mais ils doivent faire partie de myResult, non? Accédez-les comme suit:

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

Un certain nombre d'autres méthodes Queryable pourraient également être utilisées.

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) 
-2

Lorsque vous utilisez groupe par Linq crée une nouvelle collection d'articles si vous avez deux collections d'objets.

est ici une solution aux deux problèmes:

  1. somme toute quantité de membres dans une itération et
  2. éviter de dupliquer votre collection article

code:

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; 
    } 
    } 
} 

Voici la façon dont vous devez faire la sommation:

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

Voici un exemple général:

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); 

comme vous pouvez le voir

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

Cela a été déjà répondu, mais les autres réponses seront encore faire plusieurs itérations sur la collection (plusieurs appels Sum) ou créer beaucoup d'objets intermédiaires/Tuples qui peuvent être bien, mais si ce n'est pas le cas, vous pouvez créer une méthode d'extension (ou multiple) qui le fait à l'ancienne mais s'intègre bien dans une expression LINQ.

Une telle méthode d'extension ressemblerait à ceci:

public static Tuple<int, int> Sum<T>(this IEnumerable<T> collection, Func<T, int> selector1, Func<T, int> selector2) 
{ 
    int a = 0; 
    int b = 0; 

    foreach(var i in collection) 
    { 
     a += selector1(i); 
     b += selector2(i); 
    } 

    return Tuple.Create(a, b); 
} 

Et vous pouvez l'utiliser comme ceci:

public class Stuff 
{ 
    public int X; 
    public int Y; 
} 

//... 

var stuffs = new List<Stuff>() 
{ 
    new Stuff { X = 1, Y = 10 }, 
    new Stuff { X = 1, Y = 10 } 
}; 

var sums = stuffs.Sum(s => s.X, s => s.Y); 
Questions connexes