2009-10-22 13 views
221

Ich habe eine Klasse Items mit properties (Id, Name, Code, Price).Entfernen Sie die Duplikate in der Liste mit linq

Die Liste der Items enthält doppelte Einträge.

Für ex .:

1   Item1  IT00001  $100 
2   Item2  IT00002  $200 
3   Item3  IT00003  $150 
1   Item1  IT00001  $100 
3   Item3  IT00003  $150 

Wie die Duplikate in der Liste entfernen mit Linq?

+0

ich eine andere Klasse als Eigenschaft haben, in den Artikel auch Klasse – Prasad

+0

Sie auch tun können, 'var set = new HashSet (); var uniques = items.Where (x => set.Add (x.Id)); '. Es sollte kriminell sein, das zu tun. – nawfal

Antwort

309
var distinctItems = items.Distinct(); 

Passend auf nur einige der Eigenschaften, einen benutzerdefinierten Gleichheitsvergleich erstellen, zB:

class DistinctItemComparer : IEqualityComparer<Item> { 

    public bool Equals(Item x, Item y) { 
     return x.Id == y.Id && 
      x.Name == y.Name && 
      x.Code == y.Code && 
      x.Price == y.Price; 
    } 

    public int GetHashCode(Item obj) { 
     return obj.Id.GetHashCode()^
      obj.Name.GetHashCode()^
      obj.Code.GetHashCode()^
      obj.Price.GetHashCode(); 
    } 
} 

es dann wie folgt verwenden:

var distinctItems = items.Distinct(new DistinctItemComparer()); 
+0

Hallo Christian, was wird die Änderung im Code sein, wenn ich eine Liste und Liste habe. Meine benutzerdefinierte Klasse hat verschiedene Elemente, in denen eine DCN-Nummer ist und die Liste nur DCN-Nummer hat. Also muss ich überprüfen, dass die Liste ein beliebiges dcn aus der Liste enthält. Angenommen, List1 = List und List2 = List . Wenn Liste1 über 2000 Elemente verfügt und Liste2 über 40000 Elemente verfügt, auf denen in Liste2 600 Elemente aus Liste1 vorhanden sind. Also in diesem Fall brauche ich 1400 als meine Ausgabe Liste als Liste1. Was wäre der Ausdruck? Vielen Dank im Voraus –

+0

Auch ein weiterer Fall ist hier, da List1 verschiedene Elemente enthält, andere Elemente Werte können unterschiedlich sein, aber die DCN muss identisch sein. In meinem Fall ist es Distinct nicht gelungen, den gewünschten Ausgang zu geben. –

+1

Ich finde Vergleichsklassen extrem nützlich. Sie können eine andere Logik als einfache Eigenschaftsnamenvergleiche ausdrücken. Ich habe letzten Monat einen neuen geschrieben, um etwas zu tun, das 'GroupBy' nicht kann. –

15

Verwenden Distinct() aber im Kopf behalten dass es den Standard-Gleichheitsvergleich verwendet, um Werte zu vergleichen. Wenn Sie also etwas darüber hinaus möchten, müssen Sie einen eigenen Vergleich implementieren.

Siehe bitte http://msdn.microsoft.com/en-us/library/bb348436.aspx für ein Beispiel.

+0

Ich sollte beachten, dass Standard-Vergleich funktioniert, wenn Kollektionstypen einer der Werttypen ist. Aber welche Standard-Gleichheit Vergleicher wählen durch csc für Referenztypen Referenztypen müssen eigene Vergleiche haben –

31

Wenn Ihre Distinct-Abfrage etwas auslöst, können Sie sich MoreLinq ansehen und den DistinctBy-Operator verwenden und verschiedene Objekte nach ID auswählen.

var distinct = items.DistinctBy(i => i.Id); 
+1

Es gibt keine DistinctBy() Methode mit Linq –

+5

@FereydoonBarikzehy Aber er ist nicht tal König über reine Linq. In Post ist Linq zu MoreLinq Projekt ... – Ademar

466
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First()); 
+21

Danke - war zu vermeiden, eine Vergleichsklasse zu schreiben, so bin ich froh, dass das funktioniert :) – Jen

+6

+1 Diese Lösung ermöglicht sogar eine Tie-Breaker: Dubletten mit Kriterien zu beseitigen! –

+4

Aber ein wenig Overhead! –

23

Dies ist, wie ich mit Linq zu Gruppe in der Lage war. Ich hoffe es hilft.

var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault()); 
+2

bereits beantwortet .. – nawfal

+2

@nawfal, schlug ich FirstOrDefault() anstelle von First() – sobelito

+9

Wenn ich richtig bin, bietet 'FirstOrDefault' hier keinen Vorteil, wenn die' Select' unmittelbar folgt 'GroupBy', da es keine Möglichkeit gibt dass es eine leere Gruppe gibt (die Gruppen wurden nur vom Inhalt der Sammlung abgeleitet) –

2
List<Employee> employees = new List<Employee>() 
{ 
    new Employee{Id =1,Name="AAAAA"} 
    , new Employee{Id =2,Name="BBBBB"} 
    , new Employee{Id =3,Name="AAAAA"} 
    , new Employee{Id =4,Name="CCCCC"} 
    , new Employee{Id =5,Name="AAAAA"} 
}; 

List<Employee> duplicateEmployees = employees.Except(employees.GroupBy(i => i.Name) 
              .Select(ss => ss.FirstOrDefault())) 
              .ToList(); 
10

Sie haben drei Optionen hier in Ihrer Liste doppeltes Element zu entfernen:

  1. eineine einen benutzerdefinierten Gleichheitsvergleich verwenden und dann Distinct(new DistinctItemComparer()) als @Christian Hayter erwähnt verwenden.
  2. Verwenden Sie GroupBy, aber bitte beachten Sie in GroupBy sollten Sie nach allen Spalten gruppieren, denn wenn Sie nur nach Id gruppieren, werden doppelte Einträge nicht immer entfernt. Zum Beispiel betrachten Sie das folgende Beispiel:

    List<Item> a = new List<Item> 
    { 
        new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100}, 
        new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200}, 
        new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}, 
        new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100}, 
        new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}, 
        new Item {Id = 3, Name = "Item3", Code = "IT00004", Price = 250} 
    }; 
    var distinctItems = a.GroupBy(x => x.Id).Select(y => y.First()); 
    

    Das Ergebnis für diese Gruppierung wird:

    {Id = 1, Name = "Item1", Code = "IT00001", Price = 100} 
    {Id = 2, Name = "Item2", Code = "IT00002", Price = 200} 
    {Id = 3, Name = "Item3", Code = "IT00003", Price = 150} 
    

    was es ist falsch, weil es {Id = 3, Name = "Item3", Code = "IT00004", Price = 250} als Duplikat betrachtet. Die richtige Abfrage wäre also:

    3.Außer Kraft setzen Equal und GetHashCode in Artikel Klasse:

    public class Item 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 
        public string Code { get; set; } 
        public int Price { get; set; } 
    
        public override bool Equals(object obj) 
        { 
         if (!(obj is Item)) 
          return false; 
         Item p = (Item)obj; 
         return (p.Id == Id && p.Name == Name && p.Code == Code && p.Price == Price); 
        } 
        public override int GetHashCode() 
        { 
         return String.Format("{0}|{1}|{2}|{3}", Id, Name, Code, Price).GetHashCode(); 
        } 
    } 
    

    Dann Sie es wie folgt verwenden können:

    var distinctItems = a.Distinct(); 
    
1

Versuchen Sie, diese Erweiterungsmethode aus. Hoffentlich könnte das helfen.

public static class DistinctHelper 
{ 
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
    { 
     var identifiedKeys = new HashSet<TKey>(); 
     return source.Where(element => identifiedKeys.Add(keySelector(element))); 
    } 
} 

Verbrauch:

var outputList = sourceList.DistinctBy(x => x.TargetProperty); 
0

Wenn Sie IEqualityComparer nicht schreiben wollen, können Sie versuchen, so etwas wie folgt.

class Program 
{ 

    private static void Main(string[] args) 
    { 

     var items = new List<Item>(); 
     items.Add(new Item {Id = 1, Name = "Item1"}); 
     items.Add(new Item {Id = 2, Name = "Item2"}); 
     items.Add(new Item {Id = 3, Name = "Item3"}); 

     //Duplicate item 
     items.Add(new Item {Id = 4, Name = "Item4"}); 
     //Duplicate item 
     items.Add(new Item {Id = 2, Name = "Item2"}); 

     items.Add(new Item {Id = 3, Name = "Item3"}); 

     var res = items.Select(i => new {i.Id, i.Name}) 
      .Distinct().Select(x => new Item {Id = x.Id, Name = x.Name}).ToList(); 

     // now res contains distinct records 
    } 



} 


public class Item 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 
} 
0

Ein Universal-Extension-Methode:

public static class EnumerableExtensions 
{ 
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector) 
    { 
     return enumerable.GroupBy(keySelector).Select(grp => grp.First()); 
    } 
} 

Anwendungsbeispiel:

var lstDst = lst.DistinctBy(g => g.Key); 
Verwandte Themen