如何对IEnumerable使用组合键选择器

本文关键字:组合 选择器 IEnumerable | 更新日期: 2023-09-27 18:05:39

我正在寻找通过列表项的IEnumerable属性来分组列表项的最简单方法。例如列表包含产品,每个产品包含升级列表。如果两个产品具有相同的id,并且它们的升级属性包含相同的id,则应该对它们进行分组。我设法用自定义的EqualityComparer做到了这一点,但我想知道是否有更简单的方法来做到这一点?

我当前的工作代码:

public class Product
 {
    public int ProductId { get; set; }
    public string Name { get; set; }
    public IEnumerable<Upgrade> Upgrades { get; set; }
 }
 public class Upgrade
 {
    public int Id { get; set; }
    public string Name { get; set; }
 }
 public class ProductsEqualityComparer : IEqualityComparer<Product>
 {      
    public bool Equals(Product x, Product y)
    {
     bool areProductsIdsEqual = x.ProductId == y.ProductId;
     bool areUpgradesEqual = new HashSet<int>(x.Upgrades.Select(u => u.Id)).SetEquals(y.Upgrades.Select(u2 => u2.Id));
     return areProductsIdsEqual && areUpgradesEqual;
    }
    public int GetHashCode(Product obj)
    {
     int hash = obj.ProductId.GetHashCode();
     foreach (var upgrade in obj.Upgrades)
     {
        hash ^= upgrade.Id.GetHashCode();
     }
     return hash;
    }
 }

那么我就这样命名它:

var grouped = productList.GroupBy(l => l, new ProductsEqualityComparer());

致所有Linq大师——有没有更简单/更好的方法来做到这一点?

如何对IEnumerable<T>使用组合键选择器

您自己的解决方案可能是最有效的。但是,如果您能够负担得起在产品上创建额外的包装器并对这些包装器进行分组,那么还有另一种选择,例如:

var grouped = productList.Select(p => new {
        GroupId = p.ProductId.ToString() + ";" + String.Join(",", p.Upgrades.Distinct().OrderBy(u => u)),
        Product = p
    }.GroupBy(
        p => p.GroupId, 
        p => p.Product
    );

但是,请注意,此解决方案会产生计算GroupId字符串并将所有产品包装到中间对象中的成本。为了简单起见,上面的示例使用字符串作为GroupId,如果有必要,可能还有优化的空间。