185 Stimmen

Wie man doppelte Elemente aus einer Liste mit LINQ erhält?

Ich habe eine List wie diese:

List list = new List{"6","1","2","4","6","5","1"};

Ich muss die doppelten Elemente in der Liste in eine neue Liste bekommen. Derzeit verwende ich eine verschachtelte for-Schleife dafür.

Die resultierende Liste wird {"6","1"} enthalten.

Gibt es eine Idee, dies mit LINQ oder Lambda-Ausdrücken zu tun?

11voto

explorer Punkte 10770
  Liste liste = new Liste { "6", "1", "2", "4", "6", "5", "1" };

    var q = from s in liste
            group s by s into g
            where g.Count() > 1
            select g.First();

    foreach (var item in q)
    {
        Console.WriteLine(item);

    }

10voto

Thakur Punkte 1850

Hoffentlich wird dies helfen

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };

var duplicates = listOfItems 
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);

foreach (var d in duplicates)
    Console.WriteLine(d);

3voto

Jamie L. Punkte 144

Ich versuchte dasselbe mit einer Liste von Objekten zu lösen und hatte Probleme, weil ich versuchte, die Liste der Gruppen wieder in die Original-Liste zu packen. Also entschied ich mich dafür, durch die Gruppen zu iterieren, um die Original-Liste mit Elementen, die Duplikate haben, neu zu verpacken.

public List GetDuplicatePictures()
{
    List dupes = new List();
    var grpDupes = from f in _fileRepo
                   group f by f.Length into grps
                   where grps.Count() >1
                   select grps;
    foreach (var item in grpDupes)
    {
        foreach (var thing in item)
        {
            dupes.Add(thing);
        }
    }
    return dupes;
}

0voto

Harald Coppoolse Punkte 26687

Alle bisher genannten Lösungen führen bisher ein GroupBy durch. Auch wenn ich nur den ersten Duplikat benötige, werden alle Elemente der Sammlungen mindestens einmal aufgelistet.

Die folgende Erweiterungsfunktion hört auf zu zählen, sobald ein Duplikat gefunden wurde. Es wird fortgesetzt, wenn ein nächstes Duplikat angefordert wird.

Wie immer gibt es in LINQ zwei Versionen, eine mit IEqualityComparer und eine ohne.

public static IEnumerable ExtractDuplicates(this IEnumerable source)
{
    return source.ExtractDuplicates(null);
}
public static IEnumerable ExtractDuplicates(this IEnumerable comparer);
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (comparer == null)
        comparer = EqualityCompare.Default;

    HashSet foundElements = new HashSet(comparer);
    foreach (TSource sourceItem in source)
    {
        if (!foundElements.Contains(sourceItem))
        {   // wir haben dieses sourceItem noch nicht gesehen. Fügen Sie es zu den gefundenen Elementen hinzu
            foundElements.Add(sourceItem);
        }
        else
        {   // wir haben dieses Element schon mal gesehen. Es ist ein Duplikat!
            yield return sourceItem;
        }
    }
}

Verwendung:

IEnumerable myObjects = ...

// überprüfen, ob Duplikate vorhanden sind:
bool hasDuplicates = myObjects.ExtractDuplicates().Any();

// oder die ersten drei Duplikate finden:
IEnumerable first3Duplicates = myObjects.ExtractDuplicates().Take(3)

// oder die ersten 5 Duplikate finden, die einen Namen = "MeinName" haben
IEnumerable myNameDuplicates = myObjects.ExtractDuplicates()
    .Where(duplicate => duplicate.Name == "MeinName")
    .Take(5);

Für all diese LINQ-Anweisungen wird die Sammlung nur geparst, bis die angeforderten Elemente gefunden sind. Der Rest der Sequenz wird nicht interpretiert.

Meiner Meinung nach ist das eine Effizienzsteigerung, die es zu berücksichtigen gilt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X