web-dev-qa-db-fra.com

Sélectionnez plusieurs champs par groupe et somme

Je veux faire une requête avec linq (liste d'objets) et je ne sais vraiment pas comment faire, je peux faire le groupe et la somme mais je ne peux pas sélectionner le reste des champs ..__

ID  Value     Name   Category
1   5         Name1  Category1  
1   7         Name1  Category1
2   1         Name2  Category2
3   6         Name3  Category3
3   2         Name3  Category3

Je veux grouper par ID, SUM par valeur et renvoyer tous les champs comme celui-ci.

ID  Value     Name   Category
1   12        Name1  Category1  
2   1         Name2  Category2
3   8         Name3  Category3
23
user2112420

Mise à jour: Si vous essayez d'éviter le regroupement de tous les champs, vous pouvez grouper simplement par Id:

data.GroupBy(d => d.Id)
    .Select(
        g => new
        {
            Key = g.Key,
            Value = g.Sum(s => s.Value),
            Name = g.First().Name,
            Category = g.First().Category 
        });

Mais ce code suppose que pour chaque Id, les mêmes Name et Category s'appliquent. Si tel est le cas, vous devriez envisager de normaliser comme le suggère @Aron. Cela impliquerait de conserver Id et Value dans une classe et de déplacer Name, Category (et tout autre champ qui serait identique pour la même Id) dans une autre classe, tout en ayant la valeur Id Le processus de normalisation réduit la redondance et la dépendance des données.

54
Diana Ionita
void Main()
{
            //Me being lazy in init
    var foos = new []
    {
        new Foo { Id = 1, Value = 5},
        new Foo { Id = 1, Value = 7},
        new Foo { Id = 2, Value = 1},
        new Foo { Id = 3, Value = 6},
        new Foo { Id = 3, Value = 2},
    };
    foreach(var x in foos)
    {
        x.Name = "Name" + x.Id;
        x.Category = "Category" + x.Id;
    }
            //end init.

    var result = from x in foos
                group x.Value by new { x.Id, x.Name, x.Category}
                into g
                select new { g.Key.Id, g.Key.Name, g.Key.Category, Value = g.Sum()};
    Console.WriteLine(result);
}

// Define other methods and classes here
public class Foo
{
    public int Id {get;set;}
    public int Value {get;set;}

    public string Name {get;set;}
    public string Category {get;set;}   
}
3
Aron

essaye ça:

var objList = new List<SampleObject>();

objList.Add(new SampleObject() { ID = 1, Value = 5, Name = "Name1", Category = "Catergory1"});
objList.Add(new SampleObject() { ID = 1, Value = 7, Name = "Name1", Category = "Catergory1"});
objList.Add(new SampleObject() { ID = 2, Value = 1, Name = "Name2", Category = "Catergory2"});
objList.Add(new SampleObject() { ID = 3, Value = 6, Name = "Name3", Category = "Catergory3"});
objList.Add(new SampleObject() { ID = 3, Value = 2, Name = "Name3", Category = "Catergory3"});

var newList = from val in objList
              group val by new { val.ID, val.Name, val.Category } into grouped
              select new SampleObject() { ID = grouped.ID, Value = grouped.Sum(), Name = grouped.Name, Category = grouped.Category };

vérifier avec LINQPad:

newList.Dump();
1
lexeRoy

Si votre cours est vraiment long et que vous ne voulez pas tout copier, vous pouvez essayer quelque chose comme ça:

l.GroupBy(x => x.id).
  Select(x => {
    var ret = x.First();
    ret.value = x.Sum(xt => xt.value);
    return ret;
  }).ToList();

Une grande responsabilité vient avec un grand pouvoir. Vous devez être prudent. La ligne ret.value = x.Sum(xt => xt.value) changera votre collection originale, car vous transmettez une référence, pas un nouvel objet. Si vous voulez l'éviter, vous devez ajouter une méthode Clone à votre classe telle que MemberwiseClone (mais là encore, cela créera une copie superficielle, soyez donc prudent). Afer qui vient de remplacer la ligne avec: var ret = x.First().Clone();

0
titol