So überprüfen Sie, ob das Objekt bereits in einer Liste vorhanden ist


102

Ich habe eine Liste

  List<MyObject> myList

und ich füge Elemente zu einer Liste hinzu und möchte überprüfen, ob dieses Objekt bereits in der Liste enthalten ist.

also bevor ich das mache:

 myList.Add(nextObject);

Ich möchte sehen, ob nextObject bereits in der Liste enthalten ist.

Das Objekt "MyObject" hat eine Reihe von Eigenschaften, aber der Vergleich basiert auf dem Abgleich zweier Eigenschaften.

Was ist der beste Weg, um eine Prüfung durchzuführen, bevor ich dieser Liste von "MyObject" ein neues "MyObject" hinzufüge?

Die einzige Lösung, die ich mir ausgedacht habe, war, von einer Liste in ein Wörterbuch zu wechseln und dann den Schlüssel zu einer verketteten Zeichenfolge der Eigenschaften zu machen (dies scheint ein wenig unelegant zu sein).

Irgendwelche anderen saubereren Lösungen, die list oder LINQ oder etwas anderes verwenden?

Antworten:


153

Es hängt von den Bedürfnissen der jeweiligen Situation ab. Zum Beispiel wäre der Wörterbuchansatz ziemlich gut unter der Annahme:

  1. Die Liste ist relativ stabil (nicht viele Einfügungen / Löschungen, für die Wörterbücher nicht optimiert sind)
  2. Die Liste ist ziemlich groß (ansonsten ist der Overhead des Wörterbuchs sinnlos).

Wenn die oben genannten Punkte für Ihre Situation nicht zutreffen, verwenden Sie einfach die folgende Methode Any():

Item wonderIfItsPresent = ...
bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);

Dies wird durch die Liste aufgelistet, bis eine Übereinstimmung gefunden wird oder bis das Ende erreicht ist.


Die Verwendung eines Prädikatdelegaten für die list.exists ist eine weitere Lösung (siehe unten). Wenn Sie jedoch große Listen und Schlüsselwerte mit einem Wörterbuch haben, ist dies viel schneller, da es sich um eine Hash-Tabelle handelt! Viel Spaß
Doug

1
Wie überprüfe ich mehrere Werte?
Nitin Karale

78

Verwenden Sie einfach die Contains- Methode. Beachten Sie, dass es basierend auf der Gleichheitsfunktion funktioniertEquals

bool alreadyExist = list.Contains(item);

5
Das hat bei mir nicht funktioniert, es hat immer gesagt, dass es nicht existiert
Si8

4
@ Si8 Wenn Sie versuchen, Objekte zu vergleichen, müssen Sie sicherstellen, dass die Implementierung von IEquatable <T> .Equals für den Objekttyp ordnungsgemäß implementiert ist. Andernfalls werden Sie den Objektinhalt nicht vergleichen. Unter dem Link "Enthält Ahmad" finden Sie ein Beispiel für die Implementierung.
Doug Knudsen

55

Wenn es wartbar ist, diese beiden Eigenschaften zu verwenden, können Sie:

bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");

7

Sind Sie sicher, dass Sie in diesem Fall eine Liste benötigen? Wenn Sie die Liste mit vielen Elementen füllen, leidet die Leistung mit myList.Containsoder myList.Any; Die Laufzeit ist quadratisch. Möglicherweise möchten Sie eine bessere Datenstruktur verwenden. Beispielsweise,

 public class MyClass
    {
        public string Property1 { get; set; }
        public string Property2 { get; set; }

    }

    public class MyClassComparer : EqualityComparer<MyClass>
    {
        public override bool Equals(MyClass x, MyClass y)
        {
            if(x == null || y == null)
               return x == y;

            return x.Property1 == y.Property1 && x.Property2 == y.Property2;
        }

        public override int GetHashCode(MyClass obj)
        {
            return obj == null ? 0 : (obj.Property1.GetHashCode() ^ obj.Property2.GetHashCode());
        }
    }

Sie können ein HashSet folgendermaßen verwenden:

  var set = new HashSet<MyClass>(new MyClassComparer());
  foreach(var myClass in ...)
     set.Add(myClass);

Wenn diese Definition von Gleichheit für MyClass"universell" ist, müssen Sie natürlich keine IEqualityComparerImplementierung schreiben . Sie könnten einfach überschreiben GetHashCodeund Equalsin der Klasse selbst.


Ja, Bool für V war mein Favorit. Im Übrigen war es noch nicht so lange her (eh, ungefähr 3 Wochen), dass HashSet für mich nicht verfügbar war, weil ich an 2.0-Code arbeitete, und ich habe die Mono-Implementierung von HashSet eingestellt, weil es so verdammt nützlich ist :)
Jon Hanna

4

Ein weiterer zu erwähnender Punkt ist, dass Sie sicherstellen sollten, dass Ihre Gleichstellungsfunktion Ihren Erwartungen entspricht. Sie sollten die Methode equals überschreiben, um festzulegen, welche Eigenschaften Ihres Objekts übereinstimmen müssen, damit zwei Instanzen als gleich gelten.

Dann kannst du einfach mylist.contains (item) machen


3

Hier ist eine schnelle Konsolen-App, die das Konzept zur Lösung Ihres Problems darstellt.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    public class myobj
    {
        private string a = string.Empty;
        private string b = string.Empty;

        public myobj(string a, string b)
        {
            this.a = a;
            this.b = b;
        }

        public string A
        {
            get
            {
                return a;
            }
        }

        public string B
        {
            get
            {
                return b;
            }
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            List<myobj> list = new List<myobj>();
            myobj[] objects = { new myobj("a", "b"), new myobj("c", "d"), new myobj("a", "b") };


            for (int i = 0; i < objects.Length; i++)
            {
                if (!list.Exists((delegate(myobj x) { return (string.Equals(x.A, objects[i].A) && string.Equals(x.B, objects[i].B)) ? true : false; })))
                {
                    list.Add(objects[i]);
                }
            }
        }
    }
}

Genießen!


3

Edit: Ich hatte zuerst gesagt:


Was ist an der Wörterbuchlösung unelegant? Es scheint mir vollkommen elegant zu sein, zumal Sie nur den Komparator bei der Erstellung des Wörterbuchs einstellen müssen.


Natürlich ist es unelegant, etwas als Schlüssel zu verwenden, wenn es auch der Wert ist.

Daher würde ich ein HashSet verwenden. Wenn für spätere Vorgänge eine Indizierung erforderlich ist, würde ich nach dem Hinzufügen eine Liste daraus erstellen. Andernfalls verwenden Sie einfach das Hashset.


Ich würde dies nur verwenden, wenn die Liste der Objekte riesig wäre, da es sich um eine Hash-Tabelle handelt und sie sich hervorragend für schnelle Suchvorgänge eignen.
Doug

0

Einfach, aber es funktioniert

MyList.Remove(nextObject)
MyList.Add(nextObject)

oder

 if (!MyList.Contains(nextObject))
    MyList.Add(nextObject);

-1

Wenn Sie EF Core Add verwenden

 .UseSerialColumn();

Beispiel

modelBuilder.Entity<JobItem>(entity =>
        {
            entity.ToTable("jobs");

            entity.Property(e => e.Id)
                .HasColumnName("id")
                .UseSerialColumn();
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.