【问题标题】:Select multiple fields group by and sum选择多个字段分组并求和
【发布时间】:2013-04-19 08:57:53
【问题描述】:

我想使用 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

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

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

【问题讨论】:

标签: c# asp.net linq linq-group


【解决方案1】:

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

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

【讨论】:

  • 是的,我知道,但只是不想对所有字段进行分组,这将是一种不同的方式,我尝试使用 first() 但然后如何求和?
  • 是的,我知道你在说什么,我有我的数据库规范化,这只是我查询的结果,但是对于我查询的每一行,我都有重复它的值,我想要将它们分组并总结价值。
【解决方案2】:
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;}   
}

【讨论】:

  • 我知道这种方式,但我不想在我的小组中有这么多领域,我有7个以上。
  • @user2112420 然后你将不得不规范你的课程。
  • 这是我从多个表中进行的结果查询,并创建了一个这种类型的对象。
  • 我只是从不同的表中进行查询,结果将是输入一个对象,通过该查询我创建了一个对象列表,因为在每一行中我都有 ID、名称、类别、值等。
  • 如何从这些表中获得结果?如果您使用的是 ORM,您应该能够获得良好的规范化对象树。
【解决方案3】:

试试这个:

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

使用 LINQPad 检查:

newList.Dump();

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-12
      • 2017-01-08
      • 1970-01-01
      • 2022-08-02
      • 2021-10-16
      • 2021-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多