c#Linq使用int的复合键进行分组,列出<int> </int>

时间:2013-05-15 22:51:48

标签: c# linq linq-group

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

例如,以下示例数据将生成两个分组,一个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??

2 个答案:

答案 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());