7

我有两个员工列表,我只想从中获取唯一记录,但这有一个转折点。每个列表都有一个 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 名员工。名单中的两个项目的名字和姓氏匹配 - Sally Jones 和 Fred Jackson。列表中有一项不匹配,因为 FirstName 相同,但 LastName 不同:

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 属性。我想将 Joe Williams 标记为不匹配,因为两个列表中的 Smith 和 Williams 的姓氏不匹配。

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

我怎样才能成功地做我想做的事并执行这个操作?谢谢你的帮助!

4

5 回答 5

12

您使用的想法IEqualityComparer很好,是您的执行错误。值得注意的是,你的GetHashCode方法。

public int GetHashCode(Employee obj) 
{ 
    return obj.GetHashCode(); 
} 

IEqualityComparer定义两者EqualsGetHashCode 因为两者都很重要。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);
于 2012-03-23T02:37:32.503 回答
3

您可以在您的班级中覆盖Equals和。GetHashCodeEmployees

例如,

    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.
于 2012-03-23T02:35:42.480 回答
0

IEqualityComparer应该工作:

var finalResult = allFulltimeEmployees.Except(allParttimeEmployees, new EmployeeEqualityComparer());
于 2012-03-23T02:36:22.087 回答
0

尝试为您的类实现IEquatable(T)接口。Employee您只需要提供一个Equals()方法的实现,您可以根据需要定义该方法(即忽略员工 ID)。

IEquatable 接口由通用集合对象(例如 Dictionary、List 和 LinkedList)在 Contains、IndexOf、LastIndexOf 和 Remove 等方法中测试相等性时使用。应该为可能存储在通用集合中的任何对象实现它。

该方法的示例实现Equals()

public bool Equals(Employee other)
{
   return (other != null) && (FirstName == other.FirstName) && (LastName == other.LastName);
}
于 2012-03-23T02:38:31.997 回答
0

这不是最优雅的解决方案,但您可以制作这样的功能

public string GetKey(Employee emp)
{
    return string.Format("{0}#{1}", emp.FirstName, emp.LastName)
}

然后将所有内容填充allFullTimeEmployeesDictionary<string, Employee> 字典的键是调用GetKey每个员工对象的结果中。然后你可以遍历allParttimeEmployees并调用GetKey其中的每一个,探索字典(例如使用TryGetValueor ContainsKey),并对重复项采取任何必要的操作,例如从字典中删除重复项。

于 2012-03-23T02:39:27.847 回答