我正在寻找通过列表项目的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大师 - 有没有更简单/更好的方法来做到这一点?
答案 0 :(得分:3)
您自己的解决方案可能是效率最高的解决方案。但是,如果您能负担得起在产品上创建额外的包装并将这些包装器分组,还有另一种方法,例如:
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
,如果有必要,可能还有优化空间。