2013-06-07 14 views
27

Jestem w stanie usunąć duplikaty z kolekcji, mam realizowane IEqualityComparer dla pracownika klasy nadal nie jestem coraz wyjścieJak usunąć duplikaty z kolekcji za pomocą IEqualityComparer, LinQ Wyraźny

static void Main(string[] args) 
    { 
     List<Employe> Employeecollection = new List<Employe>(); 

     Employeecollection.Add(new Employe("abc","def")); 
     Employeecollection.Add(new Employe("lmn","def")); 
     Employeecollection.Add(new Employe("abc", "def")); 

     IEnumerable<Employe> coll = Employeecollection.Distinct(new Employe()); 

     foreach (Employe item in coll) 
     { 
      Console.WriteLine(item.fName + " " + item.lName); 
     } 

    } 

poniższa jest implementacja klasy pracownik, tutaj realizowane IEqualityComparer

class Employe : IEqualityComparer<Employe> 
{ 
    public string fName { get; set; } 
    public string lName { get; set; } 

    public Employe() 
    { 

    } 

    public Employe(string firstName, string LastName) 
    { 
     this.fName = firstName; 
     this.lName = LastName; 
    } 

    #region IEqualityComparer<pcf> Members 

    public bool Equals(Employe x, Employe y) 
    { 
     if (x.fName == y.fName && x.lName == y.lName) 
     { 
      return true; 
     } 

     return false; 
    } 

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

    #endregion 
} 

Odpowiedz

79

Zapomnij IEqualityComparer i po prostu używać LINQ bezpośrednio:

EmployeeCollection.GroupBy(x => new{x.fName, x.lName}).Select(g => g.First()); 
+0

Czy u proszę wyjaśnić powyższą jedną Rozumiem GroupBy ale co Select (g => g.First() – Gun

+6

Operacja GroupBy zwróci Ci IEnumerable z [IGrouping] (http://msdn.microsoft.com/en-us/library/bb344977.aspx) itemy (również IEnumerables) W przypadku twojego przykładu, w zewnętrznym IEnumerable będą znajdować się dwa elementy: jeden IGrouping z dwoma wpisami dla każdego "abc", "def", inne IGrouping z jednym wpisem dla "lmn", "def" Operator First() zabierze pierwszy element z wewnętrznych IGrouping IEnumerables – avanek

+0

dla logiki z wieloma właściwościami, musisz zgrupować we wszystkich właściwościach, które będą działały wolniej niż porównanie xor .. –

4

trzeba zastąpić GetHashCode metodę w swoim pracownikiem. Nie zrobiłeś tego. Jednym z przykładów dobrej metody haszowania podano poniżej: (generowane przez ReSharper)

public override int GetHashCode() 
{ 
    return ((this.fName != null ? this.fName.GetHashCode() : 0) * 397)^(this.lName != null ? this.lName.GetHashCode() : 0); 
} 

teraz po Distinct jest wywoływana, wydruki pętli foreach:

abc def 
lmn def 

W twoim przypadku dzwonisz klasa obiektu GetHashCode, który nic nie wie o polach wewnętrznych.

Jedna prosta uwaga, MoreLINQ zawiera DistinctBy metodę rozszerzenia, który pozwala zrobić:

IEnumerable<Employe> coll = 
Employeecollection.DistinctBy(employee => new {employee.fName, employee.lName}); 

anonimowych obiekty mają prawidłową realizację zarówno GetHashCode i Equals metod.

5

Oto dobry tutorial

public int GetHashCode(Employe obj) 
    { 
     return obj.fname.GetHashCode()^obj.lname.GetHashCode(); 
    } 
+2

Nigdy nie należy implementować GetHashCode bez wdrażania elementów równości. GetHashCode również powinien być zastąpiony. Warto również pamiętać, że * "'xor" może powodować problemy z dystrybucją lub je zwiększać, gdy istnieje nadmiarowość w strukturach danych. "*: Http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines- i-rules-for-gethashcode.aspx – spender

2

Realizacja hashcode nie jest poprawna:

public override int GetHashCode() 
{ 
    return 13 * fName.GetHashCode() + 7 * lName.GetHashCode(); 
} 
+1

czy można odbierać 'NullReferenceException' w' GetHashCode', gdy jedno z pól object ma wartość null? –

+0

Zdecydowanie nie jest - po prostu myślałem, że mogę wyjaśnić, że "hashcode powinny być takie same, gdy są takie same" fakt, niż skupić się na kontroli zerowej. Ale tak, masz rację. – aquaraga

-1
public int GetHashCode(Employe obj) 
{ 
    return obj.GetHashCode(); 
} 

Do tego metoda, zwróć hashcode właściwości, które porównujesz dla równości, zamiast samego obiektu. Porównywanie kodu kreskowego obiektów zawsze będzie false, więc twoja lista nigdy nie będzie filtrowana dla duplikatów.

0

Wygląda na to, że porównuje się przez odniesienie zamiast treści, dlatego funkcja porównania nie działa.

Zmień to, aby użyć .Equals() zamiast == i powinno działać. przykład poniżej:

#region IEqualityComparer<pcf> Members 

public bool Equals(Employe x, Employe y) 
{ 
    if (x.fName.Equals(y.fName) && x.lName.Equals(y.lName)) 
    { 
     return true; 
    } 

    return false; 
} 

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

#endregion 
+1

Operator == działa dobrze dla ciągów w języku C#. Problem dotyczy implementacji GetHashCode(). – Fredrik