53

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:

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  Value     Name   Category
1   12        Name1  Category1  
2   1         Name2  Category2
3   8         Name3  Category3
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
user2112420
  • 955
  • 5
  • 11
  • 26
  • Do you have check ? http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b and your case: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b – Aristos Apr 19 '13 at 09:01
  • since all the fields seems unique for each ID, why don't you include them in the group as well. – Habib Apr 19 '13 at 09:01
  • Yes I can do that but I have more fields than that... :( – user2112420 Apr 19 '13 at 09:13
  • go through this link.. http://stackoverflow.com/questions/847066/group-by-multiple-columns hope this will solve your problem – Utkarsh Patel Apr 19 '13 at 10:43

4 Answers4

121

Updated : If you're trying to avoid grouping for all the fields, you can group just by 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 Name and Category apply. If so, you should consider normalizing as @Aron suggests. It would imply keeping Id and Value in 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 Id for reference. The normalization process reduces data redundancy and dependency.

davmos
  • 9,324
  • 4
  • 40
  • 43
Diana Ionita
  • 3,251
  • 3
  • 27
  • 42
  • Yes I know it but just dont want to group all fields, would be a differnt way, I try with first() but then how to sum? – user2112420 Apr 19 '13 at 09:28
  • Yes I know what are you saying, I have my DB normalize, it is just a result of my query, but for each lines of my query I have repeat it values, and I want agroup them and sum the Value. – user2112420 Apr 19 '13 at 09:50
4
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;}   
}
Aron
  • 15,464
  • 3
  • 31
  • 64
2

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 change your original collection, as you are passing reference, not new object. If you want to avoid it, you need to add some Clone method 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();

titol
  • 999
  • 13
  • 25
1

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:

newList.Dump();
roybalderama
  • 1,650
  • 21
  • 38