首页 > 解决方案 > 使用 LINQ GroupBy 获取忽略属性的唯一集合

问题描述

Rules我正在尝试创建另一个Rules忽略Site属性并创建唯一列表的集合。

public class Rule
{
    public int TestId { get; set; }
    public string File { get; set; }
    public string Site { get; set; }
    public string[] Columns { get; set; }
}

因此,如果我的收藏具有如下值:

var rules = new List<Rule>
{
    new Rule { TestId = 1, File = "Foo", Site = "SiteA", Columns = new string[] { "ColA", "ColB" }},
    new Rule { TestId = 1, File = "Foo", Site = "SiteB", Columns = new string[] { "ColA", "ColB" }}
};

我想要最终的结果

var uniqueRules = new List<Rule>
{
    new Rule { TestId = 1, File = "Foo", Site = null, Columns = new string[] { "ColA", "ColB" }}
};

尝试了以下各种组合后,我仍然得到 2 个结果,如何达到预期结果?

var uniqueRules = rules
    .GroupBy(r => new { r.TestId, r.File, r.Columns })
    .Select(g => g.Key)
    .Distinct()
    .ToList();

标签: c#linq

解决方案


问题是 astring[]没有覆盖Equalsand GetHashCode,这就是为什么只比较引用的原因r.Columns。您需要提供自定义IEqualityComparer<T>

public class RuleComparer : IEqualityComparer<Rule>
{
    public bool Equals(Rule x, Rule y)
    {
        if (object.ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        if(!(x.TestId == y.TestId && x.File == y.File)) return false;
        return x.Columns.SequenceEqual(y.Columns);
    }

    // from: https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
    public int GetHashCode(Rule obj)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 23 + obj.TestId.GetHashCode();
            hash = hash * 23 + (obj.File?.GetHashCode() ?? 0);
            foreach(string s in obj.Columns)
                hash = hash * 23 + (s?.GetHashCode() ?? 0);
            return hash;
        }
    }
}

现在 LINQ 查询变得微不足道:

List<Rule> uniqueRules = rules.Distinct(new RuleComparer()).ToList();

推荐阅读