7

一意のレコードのみを取得したい 2 つの従業員リストがありますが、これにはひねりがあります。各リストには 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; }
}

一致を比較したい唯一のプロパティは、FirstName と LastName です。比較でIDを完全に無視したい。allFulltimeEmployees リストには 3 人の従業員が含まれ、allParttimeEmployees リストには 3 人の従業員が含まれています。リスト内の 2 つの項目 (Sally Jones と Fred Jackson) で名と姓が一致します。リストには、FirstName が同じで LastName が異なるため、一致しない項目が 1 つあります。

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);

したがって、2 つのリストの比較中は、クラスの ID プロパティを無視したいと考えています。2 つのリストの Smith と Williams の姓が一致しないため、Joe Williams に不一致のフラグを立てたいと思います。

// finalResult should only have Joe Williams in it 

var finalResult = allFulltimeEmployees.Except(allParttimeEmployees);

IEqualityComparer を使用してみましたが、パラメーターで IEnumerable リストではなく単一の Employee クラスを使用しているため、機能しません。

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両方が重要であるため、両方Equalsを定義します。このインターフェースを実装するときは無視しないでください。これは、等値比較において極めて重要な役割を果たします。いいえ、2 つの項目が等しいことを示すものではありませんが、2 つの要素が等しくないことを示すものです。2 つの等しい要素は、同じハッシュ コードを返す必要があります。そうでない場合、それらは等しいとは見なされません。もしそうなら、それらは等しい可能性があり、等値関数はそれからのみ探索に進みます.GetHashCode GetHashCodeEquals

実際の従業員オブジェクトのメソッドに委譲するGetHashCode実装では、従業員クラスが使用する実装に依存しています。その実装がオーバーライドされている場合にのみ、それがあなたにとって有用であり、それがあなたのキーフィールドを使用している場合にのみ役立ちます。である場合、そもそも独自の外部比較子を定義する必要がなかった可能性が非常に高いです。

重要なフィールドを考慮に入れた方法を構築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

クラスにIEquatable(T)インターフェイスを実装してみてくださいEmployee。メソッドの実装を提供する必要があるだけEquals()で、それは好きなように定義できます (つまり、従業員 ID を無視します)。

IEquatable インターフェイスは、Contains、IndexOf、LastIndexOf、Remove などのメソッドで等しいかどうかをテストするときに、Dictionary、List、LinkedList などの汎用コレクション オブジェクトによって使用されます。ジェネリック コレクションに格納される可能性のあるすべてのオブジェクトに対して実装する必要があります。

メソッドの実装例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)
}

次に、ディクショナリのキーが各従業員オブジェクトを呼び出した結果である にすべてを入力しallFullTimeEmployeesます。次に、それらのそれぞれをループして呼び出し、ディクショナリを調べ ( orを使用するなど)、ディクショナリから重複を削除するなど、重複に対して必要なアクションを実行できます。Dictionary<string, Employee>GetKeyallParttimeEmployeesGetKeyTryGetValueContainsKey

于 2012-03-23T02:39:27.847 に答える
0

あなたは動作するIEqualityComparerはずです:

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