I have a product object that has a certain location and allowable shipping methods for that product. What I'm trying to do is Group the products by location AND by the allowable ship methods.
For example the following example data would product two groupings one with IDLocation = 1 and ShipMethods of 1,2 with a count of 2 and the other would be IDLocation = 1 and ShipMethods of 1,2 with a count of 3.
public class CartProduct
{
public int IDLocation { get; set; }
public List<int> ShipMethods { get; set; }
public List<CartProduct> GetExampleData()
{
return new List<CartProduct>() { new CartProduct() { IDLocation = 1, ShipMethods = new List<int>(){ 1, 2 } },
new CartProduct() { IDLocation = 1, ShipMethods = new List<int>(){ 1, 2 } },
new CartProduct() { IDLocation = 1, ShipMethods = new List<int>(){ 3, 4 } },
new CartProduct() { IDLocation = 1, ShipMethods = new List<int>(){ 3, 4 } },
new CartProduct() { IDLocation = 1, ShipMethods = new List<int>(){ 3, 4 } }
};
}
}
I would like to see a grouping of IDLocation first, then if the ship methods are the same group those together as well.
I've tried several version of group by and select many with no luck.
List<CartProduct> CPList = new CartProduct().GetExampleData();
var GroupItems = CPList.GroupBy(x => x.IDLocation) // then by ShipMethods??
The comparer
argument in GroupBy
allows you to define equality for purposes of the object grouping. The comparer is a separate class that compares two like objects and returns true
if they are equal. The class, which needs to implement IComparer<CartItem>
, can be implemented like this:
class CartGroupComparer : IEqualityComparer<CartProduct>
{
public bool Equals(CartProduct x, CartProduct y)
{
return x.IDLocation == y.IDLocation
&& x.ShipMethods.OrderBy(x=>x)
.SequenceEqual(y.ShipMethods.OrderBy(x=>x));
}
public int GetHashCode(CartProduct obj)
{
return obj.IDLocation.GetHashCode()
^ obj.ShipMethods.Sum().GetHashCode();
}
}
(Note: for simplicity, this assumes that ShipMethods
will never be null.)
The Equals
method tests two items for equality; if equal, they will be added added to the same group. The GetHashCode
method must return an equal value for equal items, and a simple implementation is above.
You can use this comparer directly in your GroupBy
clause:
new CartProduct().GetExampleData()
.GroupBy(a => a, new CartGroupComparer());