C# 选择多个字段 group by 和 sum

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16100900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 00:00:02  来源:igfitidea点击:

Select multiple fields group by and sum

c#asp.netlinqlinq-group

提问by user2112420

I want to do a query with linq (list of objects) and I really don't know how to do it, I can do the group and the sum but can't select rest of the fields. Example:

我想用 linq(对象列表)做一个查询,但我真的不知道该怎么做,我可以做组和总和,但不能选择其余的字段。例子:

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

I want to group by ID, SUM by Value and return all fields like this.

我想按 ID、SUM 按值分组并返回所有这样的字段。

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

采纳答案by Diana Ionita

Updated : If you're trying to avoid grouping for all the fields, you can group just by Id:

更新:如果您试图避免对所有字段进行分组,则可以仅按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 
        });

But this code assumes that for each Id, the same Nameand Categoryapply. If so, you should consider normalizing as @Aron suggests. It would imply keeping Idand Valuein one class and moving Name, Category(and whichever other fields would be the same for the same Id) to another class, while also having the Idfor reference. The normalization process reduces data redundancy and dependency.

但是此代码假定对于 each Id,相同NameCategory适用。如果是这样,您应该考虑按照@Aron 的建议进行标准化。这意味着将Id和保留Value在一个类中并移动Name, Category(对于相同的任何其他字段都是相同的Id)到另一个类,同时也有Id供参考。规范化过程减少了数据冗余和依赖性。

回答by Aron

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

回答by lexeRoy

try this:

尝试这个:

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

to check with LINQPad:

使用 LINQPad 检查:

newList.Dump();

回答by titol

If your class is really long and you don't want to copy all the stuff, you can try something like this:

如果你的课真的很长而且你不想复制所有的东西,你可以尝试这样的事情:

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

With great power great responsibility comes. You need to be careful. Line ret.value = x.Sum(xt => xt.value)will changeyour original collection, as you are passing reference, not new object. If you want to avoid it, you need to add some Clonemethod into your class like MemberwiseClone(but again, this will create shallow copy, so be careful). Afer that just replace the line with: var ret = x.First().Clone();

权力越大,责任越大。你需要小心。Lineret.value = x.Sum(xt => xt.value)将更改您的原始集合,因为您传递的是引用,而不是新对象。如果你想避免它,你需要在Clone你的类中添加一些方法MemberwiseClone(但同样,这会创建浅拷贝,所以要小心)。只需将行替换为:var ret = x.First().Clone();