c# Linq通过组合键int, list分组

本文关键字:int list 分组 Linq 组合 | 更新日期: 2023-09-27 18:14:01

我有一个产品对象,它具有该产品的特定位置和允许的运输方法。我想做的是按位置和允许的运输方式对产品进行分组。

例如,下面的示例数据将产生两个分组,一个是IDLocation = 1, ShipMethods为1,2,计数为2,另一个是IDLocation = 1, ShipMethods为1,2,计数为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 } }
            };
        }
    }

我希望首先看到IDLocation的分组,然后如果船舶方法是相同的组那些在一起。

我尝试了几个版本的分组,并选择了许多没有运气。

List<CartProduct> CPList = new CartProduct().GetExampleData();
var GroupItems  = CPList.GroupBy(x => x.IDLocation) // then by ShipMethods??

c# Linq通过组合键int, list<int>分组

我认为关键是使用GroupBy的能力来指定分组时使用的"键"。你想把具有相同IDLocation和相同ShipMethods集合的东西分组在一起,所以键应该包括那些东西。理想情况下,你应该使用一个正确的比较器来做正确的事情。做这件事的一种简单的方法(更容易写,所以我可以肯定这是可行的)是把所有的东西混在一起成一个字符串,这样普通的字符串比较就能完成我们想要的。下面是简单的答案:

var answer = GetExampleData()
             .GroupBy(x=>String.Format("{0} {1}",
                         x.IDLocation,
                         String.Join(",",x.ShipMethods.OrderBy(y=>y))));

为了获得更好的性能,您必须实现我所描述的"适当"方式。这是一点工作,但它不应该太难。

edit:我正在对ShipMethods进行排序,以便可以通过1或2发送的东西被正确地视为与可以通过2或1发送的东西相同。理想情况下,ShipMethods列表已经排序,这样可以节省时间。

(时髦的格式是试图使它不滚动而可见)

GroupBy中的comparer参数允许您为对象分组的目的定义相等性。比较器是一个单独的类,它比较两个相似的对象,如果它们相等,则返回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());