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
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.
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;}
}
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();
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();