it-swarm.com.de

Suchen nach Duplikaten in einer Objektliste C #

Ich suche nach einer sehr schnellen Möglichkeit, in einer Liste von Objekten nach Duplikaten zu suchen. 

Ich dachte daran, einfach durch die Liste zu blättern und auf diese Weise einen manuellen Vergleich durchzuführen, aber ich dachte, dass linq eine elegantere Lösung bieten könnte ...

Angenommen, ich habe ein Objekt ...

public class dupeCheckee
{
     public string checkThis { get; set; }
     public string checkThat { get; set; }

     dupeCheckee(string val, string val2)
     {
         checkThis = val;
         checkThat = val2;
     }
}

Und ich habe eine Liste dieser Objekte

List<dupeCheckee> dupList = new List<dupeCheckee>();
dupList.Add(new dupeCheckee("test1", "value1"));
dupList.Add(new dupeCheckee("test2", "value1"));
dupList.Add(new dupeCheckee("test3", "value1"));
dupList.Add(new dupeCheckee("test1", "value1"));//dupe
dupList.Add(new dupeCheckee("test2", "value1"));//dupe... 
dupList.Add(new dupeCheckee("test4", "value1"));
dupList.Add(new dupeCheckee("test5", "value1"));
dupList.Add(new dupeCheckee("test1", "value2"));//not dupe

Ich muss die Dupes in dieser Liste finden. Wenn ich es finde, muss ich eine zusätzliche Logik verwenden.

Wenn ich linq benutze, wie mein GroupBy eine Ausnahme auslöst ...

'System.Collections.Generic.List<dupeCheckee>' does not contain a definition for 'GroupBy' and no extension method 'GroupBy' accepting a first argument of type 'System.Collections.Generic.List<dupeCheckee>' could be found (are you missing a using directive or an Assembly reference?)

Was sagt mir, dass ich eine Bibliothek vermisse. Es fällt mir schwer, herauszufinden, welche.

Sobald ich das herausgefunden habe, wie würde ich im Wesentlichen nach diesen beiden Bedingungen suchen? IE checkThis und checkThat beide mehr als einmal vorkommen?

UPDATE: Was mir eingefallen ist

Dies ist die linq-Abfrage, die ich nach kurzer Recherche gefunden habe ...

test.Count != test.Select(c => new { c.checkThat, c.checkThis }).Distinct().Count()

Ich bin mir nicht sicher, ob das definitiv besser ist als diese Antwort ...

var duplicates = test.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any());

Ich weiß, ich kann die erste Aussage in eine if-else-Klausel setzen. Ich habe auch einen kurzen Test gemacht. Die Liste der Duplikate gibt mir 1 zurück, als ich mit 0 gerechnet hatte, aber es wurde richtig darauf hingewiesen, dass ich Duplikate in einem der verwendeten Sets hatte ...

Die andere Methode macht genau das, was ich erwartet habe. Hier sind die Datensätze, mit denen ich das teste ....

Dupes:

List<DupeCheckee> test = new List<DupeCheckee>{ 
     new DupeCheckee("test0", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test0", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test6"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test7"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test8"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test0", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test4"),//{ checkThis = "test", checkThat = "test1"}

};

Keine Dupes ...

     List<DupeCheckee> test2 = new List<DupeCheckee>{ 
     new DupeCheckee("test0", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test5", "test6"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test6", "test7"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test7", "test8"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test8", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test9", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test4"),//{ checkThis = "test", checkThat = "test1"}

};
21
SoftwareSavant

Sie müssen auf System.Linq verweisen (z. B. using System.Linq).

dann kannst du tun

var dupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any());

Dadurch erhalten Sie Gruppen mit allen Duplikaten

Der Test auf Duplikate wäre dann

var hasDupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any()).Any();

oder rufen Sie sogar ToList() oder ToArray() an, um die Berechnung des Ergebnisses zu erzwingen. Anschließend können Sie sowohl nach Dupes suchen als auch nach ihnen suchen.

z.B..

var dupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any()).ToArray();
if (dupes.Any()) {
  foreach (var dupeList in dupes) {
    Console.WriteLine(string.Format("checkThis={0},checkThat={1} has {2} duplicates",
                      duplist.Key.checkThis, 
                      duplist.Key.checkThat,
                      duplist.Count() - 1));
  }

}

Alternative

var dupes = dupList.Select((x, i) => new { index = i, value = x})
                   .GroupBy(x => new {x.value.checkThis, x.value.checkThat})
                   .Where(x => x.Skip(1).Any());

Welche geben Ihnen die Gruppen, bei denen jeder Artikel pro Gruppe den ursprünglichen Index in einer Eigenschaft index und den Artikel in der Eigenschaft value speichert. 

36
Bob Vale

Es gab sehr viele funktionierende Lösungen, aber ich denke, dass die nächste Lösung transparenter und leichter zu verstehen sein wird.

var hasDuplicatedEntries = ListWithPossibleDuplicates
                                   .GroupBy(YourGroupingExpression)
                                   .Any(e => e.Count() > 1);
if(hasDuplicatedEntries)
{
   // Do what ever you want in case when list contains duplicates 
}
8
Maris

Ich denke, das ist was Sie suchen:

List<dupeChecke> duplicates = dupeList.GroupBy(x => x)
                                   .SelectMany(g => g.Skip(1));
1
Captain Skyhawk

Ich benutze dies gerne, um zu wissen, ob es überhaupt Duplikate gibt. Nehmen wir an, Sie hätten eine Zeichenfolge und wollten wissen, ob doppelte Buchstaben vorhanden sind. Das ist was ich benutze.

string text = "this is some text";

var hasDupes = text.GroupBy(x => x).Any(grp => grp.Count() > 1);

Wenn Sie wissen möchten, wie viele Duplikate es gibt, egal welche Duplikate sind, verwenden Sie diese Option. 

var totalDupeItems = text.GroupBy(x => x).Count(grp =>  grp.Count() > 1);

"Zum Beispiel ist dies ein Text", hat dies ...

buchstabe t insgesamt: 3

buchstabe i insgesamt: 2

buchstaben insgesamt: 3

buchstabe e insgesamt: 2

Die Variable totalDupeItems wäre also gleich 4. Es gibt 4 verschiedene Arten von Duplikaten.

Wenn Sie die Gesamtmenge der Dup-Objekte unabhängig von den Dup-Objekten abrufen möchten, verwenden Sie diese Option.

var totalDupes = letters.GroupBy(x => x).Where(grp => grp.Count() > 1).Sum(grp => grp.Count());

Die Variable totalDupes wäre also 10. Dies ist die Summe aller doppelten Elemente jedes Dupe-Typs.

0

Wenn ein Duplikat auftritt, wird eine Ausnahme ausgelöst. Das Wörterbuch prüft die Schlüssel von selbst. Dies ist der einfachste Weg.

try
{
  dupList.ToDictionary(a=>new {a.checkThis,a.checkThat});
}
catch{
 //message: list items is not uniqe
}
0
Isomiddin

Für Speicherobjekte verwende ich immer die Distinct LINQ-Methode, um der Lösung einen Vergleicher hinzuzufügen.

public class dupeCheckee
{
     public string checkThis { get; set; }
     public string checkThat { get; set; }

     dupeCheckee(string val, string val2)
     {
         checkThis = val;
         checkThat = val2;
     }

     public class Comparer : IEqualityComparer<dupeCheckee>
     {
         public bool Equals(dupeCheckee x, dupeCheckee y)
         {
             if (x == null || y == null)
                 return false;

             return x.CheckThis == y.CheckThis && x.CheckThat == y.CheckThat;
         }

         public int GetHashCode(dupeCheckee obj)
         {
             if (obj == null)
                 return 0;

             return (obj.CheckThis == null ? 0 : obj.CheckThis.GetHashCode()) ^
                 (obj.CheckThat == null ? 0 : obj.CheckThat.GetHashCode());
         }
     }
}

Jetzt können wir anrufen

List<dupeCheckee> dupList = new List<dupeCheckee>();
dupList.Add(new dupeCheckee("test1", "value1"));
dupList.Add(new dupeCheckee("test2", "value1"));
dupList.Add(new dupeCheckee("test3", "value1"));
dupList.Add(new dupeCheckee("test1", "value1"));//dupe
dupList.Add(new dupeCheckee("test2", "value1"));//dupe... 
dupList.Add(new dupeCheckee("test4", "value1"));
dupList.Add(new dupeCheckee("test5", "value1"));
dupList.Add(new dupeCheckee("test1", "value2"));//not dupe

var distinct = dupList.Distinct(dupeCheckee.Comparer);
0
Arturo Martinez

Wählen Sie mit linq eine Auswahl aus, z. Wie kann ich SELECT UNIQUE mit LINQ auswählen?

Und vergleichen Sie dann die Zählungen der unterschiedlichen Ergebnisse mit den nicht unterschiedlichen Ergebnissen. Das gibt Ihnen ein boolesches Sprichwort, wenn die Liste doppelt ist.

Sie können auch versuchen, ein Wörterbuch zu verwenden, um sicherzustellen, dass der Schlüssel eindeutig ist.

0
MatthewMartin