使用 Linq 对两个属性进行分组

5

假设我有一个订单列表。每个订单都有对客户和他们购买的产品的引用。像这样:

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

我想将所有拥有相同产品集的不同客户的订单分为同一组。
  • 客户1 - 产品1&2
  • 客户2 - 产品1&2&3
  • 客户3 - 产品1&2
  • 客户4 - 产品3&4&5
在这种情况下,客户1和3的订单将被分为同一组,而客户2和4的订单将有各自的组。
使用LINQ实现这个功能是否可行?我尝试按CustomerId进行分组,但不知道如何继续。

我猜测我的理解是正确的,即每个客户可能有任意数量的产品(您的示例似乎暗示每个客户只能有两个产品)。 - Jason Boyd
@Nait 那么您希望对其进行什么样的分组呢?随着越来越多的产品被添加/移除,这不会不断改变分组吗?也许我没有理解您想要实现的目标,但这对我来说似乎有点不太合适。 - David L
2
如果客户1有三个订单,其中一个是重复的:产品1&2&1,那么如果他的订单是:产品1&2,那么这个订单应该与客户2分组吗? - Cory
@David 我正在从数据库中检索订单并根据数据创建一个输出文件。在此过程中不会添加/删除产品。 - Nait
@Cory 在我的情况下没有重复项。 - Nait
显示剩余2条评论
1个回答

7

需要:

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查询:

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

这里是比较器。
 public class IntArrayComparer : IEqualityComparer<int[]>
 {    
     public bool Equals(int[] x, int[] y)
     {
         return x.SequenceEqual(y);
     }

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

编辑:如果您正在寻找更智能的GetHashCode函数,您可以尝试类似以下代码:

public int GetHashCode(int[] obj)
{
    return string.Join(",", obj.Select(i => i.ToString())).GetHashCode();
}

如果客户1有三个订单,其中一个是重复的:产品1&2&1,而客户2的订单是产品1&2,那么它们应该分为同一组吗?如果它们仍然应该在同一组中,我认为你需要在选择每个客户的ProductIds之后加上.Distinct() - Cory
我不确定哈希函数是否有效。具有相同内容的两个不同数组应该具有相同的哈希值(与顺序无关),但我认为它并没有?http://csharppad.com/gist/8068d2183d4d6624cf61 - Caramiriel
@Cory他没有说这些订单必须在同一组中还是不同组,我认为这并不是这个问题的主要关注点。但无论如何,正如您所知,如果他想忽略重复的订单,他可以使用Distinct()函数。 - Hossein Narimani Rad
你应该使用更智能的方法来实现 GetHashCode。现在你只是为任何数组返回相同的值。虽然这是有效的(两个相等的数组具有相等的哈希码),但它意味着 GroupBy 使用的哈希表算法会退化为线性搜索。 - user4003407

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接