wake-up-neo.com

Wählen Sie mehrere Felder gruppieren nach und Summe aus

Ich möchte eine Abfrage mit linq (Liste der Objekte) durchführen und weiß wirklich nicht, wie ich das machen soll, ich kann die Gruppe und die Summe machen, aber ich kann die restlichen Felder nicht auswählen . Beispiel:

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

Ich möchte nach ID gruppieren, SUM nach Wert und alle Felder so zurückgeben.

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

Aktualisiert: Wenn Sie versuchen, die Gruppierung für alle Felder zu vermeiden, können Sie die Gruppierung einfach nach 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 
        });

In diesem Code wird jedoch davon ausgegangen, dass für jede Id dieselbe Name und Category gilt. Wenn ja, sollten Sie eine Normalisierung in Betracht ziehen, wie von @Aron vorgeschlagen. Es würde bedeuten, Id und Value in einer Klasse zu behalten und Name, Category (und welche anderen Felder für dieselbe Id) auch in eine andere Klasse passen würden, während die Id zur Referenz vorhanden ist. Der Normalisierungsprozess reduziert die Datenredundanz und -abhängigkeit.

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

versuche dies:

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

mit LINQPad überprüfen:

newList.Dump();
1
lexeRoy

Wenn Ihre Klasse wirklich lang ist und Sie nicht all das Zeug kopieren möchten, können Sie Folgendes versuchen:

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

Mit großer Kraft kommt große Verantwortung. Du musst vorsichtig sein. Zeile ret.value = x.Sum(xt => xt.value) ändert Ihre ursprüngliche Sammlung, wenn Sie einen Verweis übergeben, nicht ein neues Objekt. Wenn Sie dies vermeiden möchten, müssen Sie Ihrer Klasse eine Clone-Methode wie MemberwiseClone hinzufügen. Dann ersetzen Sie einfach die Zeile mit: var ret = x.First().Clone();

0
titol