Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq groupby on two properties

Tags:

c#

linq

Say I have a list of orders. Each order have a reference to the customer and the product they bought. Like so:

class Orders 
{
    public int CustomerId {get;set;}
    public int ProductId {get;set;}
}

I want to group all orders where different customers have the same set of products are in the same group.

  • Customer 1 - Product 1&2
  • Customer 2 - Product 1&2&3
  • Customer 3 - Product 1&2
  • Customer 4 - Product 3&4&5

In this case, the orders for customer 1&3 will be in the same group, and orders for 2&4 will have their own group.

Is this possible to achieve with LINQ? I started with trying to group by the CustomerId, but am at a lost on how to proceed from there.

like image 745
Nait Avatar asked May 22 '15 14:05

Nait


1 Answers

Having:

List<Orders> orders = new List<Orders>();

orders.Add(new Orders { CustomerId = 1, ProductId = 1 });
orders.Add(new Orders { CustomerId = 1, ProductId = 2 });
orders.Add(new Orders { CustomerId = 2, ProductId = 2 });
orders.Add(new Orders { CustomerId = 2, ProductId = 3 });
orders.Add(new Orders { CustomerId = 3, ProductId = 1 });
orders.Add(new Orders { CustomerId = 3, ProductId = 2 });
orders.Add(new Orders { CustomerId = 4, ProductId = 3 });
orders.Add(new Orders { CustomerId = 4, ProductId = 4 });

LINQ Query:

 var groupedCustomers = 
         orders.GroupBy(i => i.CustomerId)
               .Select(i => new { CUSTOMER = i.Key, 
                                  ORDERS = i.Select(j => j.ProductId)
                                            .OrderBy(j => j)
                                          //.Distinct() to ignore duplicate orders
                                            .ToArray() })
               .ToList();

 var result = groupedCustomers.GroupBy(i => i.ORDERS, new IntArrayComparer()).ToList();

And here is the comparer.

 public class IntArrayComparer : IEqualityComparer<int[]>
 {    
     public bool Equals(int[] x, int[] y)
     {
         return x.SequenceEqual(y);
     }

     public int GetHashCode(int[] obj)
     {
         return base.GetHashCode();
     }
 }

EDIT: If you are looking for smarter GetHashCode function, you may try something like this:

public int GetHashCode(int[] obj)
{
    return string.Join(",", obj.Select(i => i.ToString())).GetHashCode();
}
like image 79
Hossein Narimani Rad Avatar answered Oct 22 '22 08:10

Hossein Narimani Rad