Search code examples
c#linqgethashcodeiequalitycomparer

Linq Group by Complex Object (E.G list element of object)


I have an object like below;

var json = @"{
  'TableNumber': '3',
  'TableId': '81872d39-9480-4d2d-abfc-b8e4f33a43b6',
  'tableMenuItems': [
    {
      'Id': '4664a2d3-c0af-443d-8af5-2bd21e71838b',
      'Name': 'Bonfile',
      'tableMenuItemCondiment': [
        {
          'Id': '9b1f01a0-0313-46b6-b7f1-003c0e846136',
          'Name': 'Kekikkli',
          'Price': 0
        },
        {
          'Id': '38a9cce6-f20c-4f78-b6c9-c15e79ecc8f1',
          'Name': 'mayonez',
          'Price': 0
        },
        {
          'Id': 'cb3a7811-668b-4e45-bce3-e6b2b13af9e1',
          'Name': 'Rare',
          'Price': 0
        }
      ],
      'Price': 45,
      'Count': 1
    },
    {
      'Id': '4664a2d3-c0af-443d-8af5-2bd21e71838b',
      'Name': 'Bonfile',
      'tableMenuItemCondiment': [
        {
          'Id': 'c3c62f7d-987d-4523-849c-932334db4e4f',
          'Name': 'Kekikkli',
          'Price': 0
        },
        {
          'Id': 'cbb16028-6e77-4e4b-a1c9-d969e804f093',
          'Name': 'mayonez',
          'Price': 0
        },
        {
          'Id': '16f9efc2-73d3-4a09-87fc-e1fb76957ed2',
          'Name': 'Rare',
          'Price': 0
        }
      ],
      'Price': 45,
      'Count': 1
    }
  ],
  'TotalPrice': 90
}";

As you see above, the object has element of list as tableMenuItems. There are two object in tableMenuItems property and this are completly identical. I want to group this object like below;

var json = @"{
  'TableNumber': '3',
  'TableId': '81872d39-9480-4d2d-abfc-b8e4f33a43b6',
  'tableMenuItems': [
    {
      'Id': '4664a2d3-c0af-443d-8af5-2bd21e71838b',
      'Name': 'Bonfile',
      'tableMenuItemCondiment': [
        {
          'Id': '9b1f01a0-0313-46b6-b7f1-003c0e846136',
          'Name': 'Kekikkli',
          'Price': 0
        },
        {
          'Id': '38a9cce6-f20c-4f78-b6c9-c15e79ecc8f1',
          'Name': 'mayonez',
          'Price': 0
        },
        {
          'Id': 'cb3a7811-668b-4e45-bce3-e6b2b13af9e1',
          'Name': 'Rare',
          'Price': 0
        }
      ],
      'Price': 90,
      'Count': 2
    }    
  ],
  'TotalPrice': 90
}";

As you see if two tablemenuitems is same and their condiment is same i grouping them. I made some IEqualityComparer for gruping but it's not work what i excepted.

Here is what i did you see below link;

https://dotnetfiddle.net/QQFfIy

I don't understand what i did wrong


Solution

  • 1 ) I've created my classes to meet json,

    public class MyTable {
        public string TableNumber { get; set; }
        public string TableId { get; set; }
        public List<TableMenu> tableMenuItems { get; set; }
        public int TotalPrice { get; set; }
    }
    
    public class TableMenu {
        public string Id { get; set; }
        public string Name { get; set; }
        public List<TableMenuItemCondiment> tableMenuItemCondiment { get; set; }
        public int Price { get; set; }
        public int Count { get; set; }
    }
    
    public class TableMenuItemCondiment {
        public string Id { get; set; }
        public string Name { get; set; }
        public int Price { get; set; }
    }
    

    2 ) Then i've deserialized object by NewtonSoft,

    MyTable myTable = JsonConvert.DeserializeObject<MyTable>(json);
    

    3 ) Converted object as,

    MyTable result = new MyTable() {
                    TableNumber = myTable.TableNumber,
                    TableId = myTable.TableId,
                    tableMenuItems = myTable.tableMenuItems.GroupBy(x => x.Id).Select(x => new TableMenu() {
                        Id = x.Key,
                        Name = x.First()?.Name,
                        tableMenuItemCondiment = x.SelectMany(a=>a.tableMenuItemCondiment).GroupBy(z => z.Name).Select(z => new TableMenuItemCondiment() {
                            Id = z.First()?.Id,
                            Name = z.Key,
                            Price = z.Sum(t => t.Price)
                        }).ToList(),
                        Price = x.Sum(t => t.Price),
                        Count = x.Sum(t => t.Count)
                    }).ToList(),
                    TotalPrice = myTable.TotalPrice
                };
    

    4 ) Finally serialized object to see whether it gives the response as you want,

    string output = JsonConvert.SerializeObject(result);
    

    5 ) Print the output,

    Console.WriteLine(output);
    Console.ReadKey();
    

    Output:

    {  "TableNumber":"3", 
      "TableId":"81872d39-9480-4d2d-abfc-b8e4f33a43b6", 
      "tableMenuItems":[
         {
            "Id":"4664a2d3-c0af-443d-8af5-2bd21e71838b",
            "Name":"Bonfile",
            "tableMenuItemCondiment":[
               {
                  "Id":"9b1f01a0-0313-46b6-b7f1-003c0e846136",
                  "Name":"Kekikkli",
                  "Price":0
               },
               {
                  "Id":"38a9cce6-f20c-4f78-b6c9-c15e79ecc8f1",
                  "Name":"mayonez",
                  "Price":0
               },
               {
                  "Id":"cb3a7811-668b-4e45-bce3-e6b2b13af9e1",
                  "Name":"Rare",
                  "Price":0
               }
            ],
            "Price":90,
            "Count":2
         }    
    ],    
    "TotalPrice":90 }