比较两个列表并忽略特定属性
本文关键字:属性 列表 两个 比较 | 更新日期: 2023-09-27 18:28:57
>我有两个员工列表,我只想从中获取唯一的记录,但这有一个转折点。每个列表中都有一个 Employee 类:
public class Employee
{
// I want to completely ignore ID in the comparison
public int ID{ get; set; }
// I want to use FirstName and LastName in comparison
public string FirstName{ get; set; }
public string LastName{ get; set; }
}
我想比较匹配的唯一属性是名字和姓氏。我想在比较中完全忽略 ID。allFulltimeEmployees列表有3名员工,allParttimeEmployees列表中有3名员工。名字和姓氏与列表中的两个项目匹配 - 莎莉琼斯和弗雷德杰克逊。列表中有一个项目不匹配,因为名字相同,但姓氏不同:
emp.id = null; // not populated or used in comparison
emp.FirstName = "Joe"; // same
emp.LastName = "Smith"; // different
allFulltimeEmployees.Add(emp);
emp.id = 3; // not used in comparison
emp.FirstName = "Joe"; // a match
emp.LastName = "Williams"; // not a match - different last name
allParttimeEmployees.Add(emp);
所以我想在比较两个列表时忽略类中的 ID 属性。我想将乔·威廉姆斯标记为不匹配,因为两个名单中史密斯和威廉姆斯的姓氏不匹配。
// finalResult should only have Joe Williams in it
var finalResult = allFulltimeEmployees.Except(allParttimeEmployees);
我尝试使用 IEqualityComparer,但它不起作用,因为它在参数中使用单个 Employee 类而不是 IEnumerable 列表:
public class EmployeeEqualityComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
if (x.FirstName == y.FirstName && x.LastName == y.LastName)
{
return true;
}
else
{
return false;
}
}
public int GetHashCode(Employee obj)
{
return obj.GetHashCode();
}
}
如何才能成功地执行我想要的操作并执行此操作?感谢您的任何帮助!
你使用IEqualityComparer
的想法很好,你的执行是错误的。值得注意的是,您的GetHashCode
方法。
public int GetHashCode(Employee obj)
{
return obj.GetHashCode();
}
IEqualityComparer
定义了Equals
和GetHashCode
,因为两者都很重要。实现此接口时不要忽略GetHashCode
!它在平等比较中起着关键作用。不,它并不表示两个项目相等,但它表明两个元素不相等。两个相等的元素必须返回相同的哈希代码。如果它们不这样做,则不能认为它们是平等的。如果他们这样做,那么他们可能是相等的,而相等函数只有这样才能继续探索Equals
。
通过将实现委托给实际员工对象的GetHashCode
方法,您将依赖于 Employee 类使用的实现。只有当该实现被覆盖时,它才会对您有用,并且仅当它使用您的关键字段时。如果是,那么您很可能一开始就不需要定义自己的外部比较器!
构建一个将关键字段考虑在内GetHashCode
方法,您将被设置。
public int GetHashCode(Employee obj)
{
// null handling omitted for brevity, but you will want to
// handle null values appropriately
return obj.FirstName.GetHashCode() * 117
+ obj.LastName.GetHashCode();
}
使用此方法后,请在调用 Except
时使用比较器。
var comparer = new EmployeeEqualityComparer();
var results = allFulltimeEmployees.Except(allParttimeEmployees, comparer);
您可以在Employees
类中覆盖Equals
和GetHashCode
。
例如
public class Employee
{
// I want to completely ignore ID in the comparison
public int ID { get; set; }
// I want to use FirstName and LastName in comparison
public string FirstName { get; set; }
public string LastName { get; set; }
public override bool Equals(object obj)
{
var other = obj as Employee;
return this.FirstName == other.FirstName && this.LastName == other.LastName;
}
public override int GetHashCode()
{
return this.FirstName.GetHashCode() ^ this.LastName.GetHashCode();
}
}
我使用以下数据集进行了测试:
var empList1 = new List<Employee>
{
new Employee{ID = 1, FirstName = "D", LastName = "M"},
new Employee{ID = 2, FirstName = "Foo", LastName = "Bar"}
};
var empList2 = new List<Employee>
{
new Employee { ID = 2, FirstName = "D", LastName = "M" },
new Employee { ID = 1, FirstName = "Foo", LastName = "Baz" }
};
var result = empList1.Except(empList2); // Contained "Foo Bar", ID #2.
你的IEqualityComparer
应该可以工作:
var finalResult = allFulltimeEmployees.Except(allParttimeEmployees, new EmployeeEqualityComparer());
尝试为Employee
类实现 IEquatable(T( 接口。您只需要为Equals()
方法提供一个实现,您可以根据需要定义该方法(即忽略员工 ID(。
IEquatable 接口由泛型集合对象使用,例如 测试时作为字典、列表和链接列表 在诸如 Contains、IndexOf、LastIndexOf 和 删除。应该为可能存储的任何对象实现它 在泛型集合中。
Equals()
方法的示例实现:
public bool Equals(Employee other)
{
return (other != null) && (FirstName == other.FirstName) && (LastName == other.LastName);
}
这不是最优雅的解决方案,但你可以做一个这样的函数
public string GetKey(Employee emp)
{
return string.Format("{0}#{1}", emp.FirstName, emp.LastName)
}
然后将allFullTimeEmployees
中的所有内容填充到一个Dictionary<string, Employee>
中,其中字典的键是对每个员工对象调用GetKey
的结果。 然后,您可以遍历allParttimeEmployees
并调用GetKey
,探测字典(例如,使用 TryGetValue
或 ContainsKey
(,并对副本采取任何必要的操作,例如从字典中删除副本。