我有一个产品对象,该产品对象具有该产品的特定位置和允许的运输方式。我想要做的是按地点和允许的船舶方法对产品进行分组。
例如,以下示例数据将生成两个分组,一个IDLocation = 1,ShipMethods为1,2,计数为2,另一个分别为IDLocation = 1和ShipMethods为1,2,计数为3。 / p>
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 } }
};
}
}
我希望首先看到IDLocation的分组,然后如果发货方法也是同一组,那么它们也是。
我尝试了几个版本的group by并选择了许多没有运气的版本。
List<CartProduct> CPList = new CartProduct().GetExampleData();
var GroupItems = CPList.GroupBy(x => x.IDLocation) // then by ShipMethods??
答案 0 :(得分:2)
我认为关键是使用GroupBy能够指定分组时使用的“密钥”。您希望将具有相同IDLocation和相同ShipMethods集合的事物组合在一起,因此密钥应包含这些内容。理想情况下,你会使用一个正确的比较器来做正确的事情。执行此操作的hackish方式(更容易编写,所以我可以告诉它'可行)是将所有内容混合成一个字符串,以便正常的字符串比较完成我们想要的。所以这是快速回答:
var answer = GetExampleData()
.GroupBy(x=>String.Format("{0} {1}",
x.IDLocation,
String.Join(",",x.ShipMethods.OrderBy(y=>y))));
为了获得更好的性能,您必须实现我所描述的“正确”方式。这有点工作,但不应该太难。
编辑:我正在对ShipMethods进行排序,以便可以通过1或2运送的东西正确地看作是可以通过2或1运送的东西。理想情况下ShipMethods列表已经排序,所以我们可以节省时间。
(时髦的格式是尝试在不滚动的情况下使其可见)
答案 1 :(得分:1)
comparer
中的GroupBy
参数允许您为对象分组定义相等性。比较器是一个单独的类,它比较两个相似的对象,如果它们相等则返回true
。需要实现IComparer<CartItem>
的类可以像这样实现:
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();
}
}
(注意:为简单起见,假设ShipMethods
永远不会为空。)
Equals
方法测试两个项是否相等;如果相等,它们将被添加到同一组中。 GetHashCode
方法必须为相等的项返回相等的值,并且上面有一个简单的实现。
您可以直接在GroupBy
子句中使用此比较器:
new CartProduct().GetExampleData()
.GroupBy(a => a, new CartGroupComparer());