2010-08-08 36 views
53

Ich habe eine Listewie überprüfen, ob Objekt existiert bereits in einer Liste

List<MyObject> myList 

und ich bin das Hinzufügen von Elementen zu einer Liste und ich mag überprüfen, ob das Objekt bereits in der Liste enthalten ist.

so, bevor ich dies tun:

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 der Übereinstimmung zweier Eigenschaften.

was ist der beste Weg, um einen Scheck zu tun, bevor ich ein neues „MyObject“ zu Thsi Liste der „MyObject“ add s

die einzige Lösung, die ich erdacht wurde aus einer Liste zu einem Wörterbuch zu ändern und Machen Sie den Schlüssel eine verkettete Zeichenfolge der Eigenschaften (das scheint ein wenig unelegant)

andere Reiniger-Lösungen mit Liste oder LINQ oder etwas anderes?

Antwort

96

Es hängt von den Bedürfnissen der spezifischen Situation ab. Zum Beispiel würde das Wörterbuch Ansatz recht gut angenommen:

  1. Die Liste ist relativ stabil (nicht viele Einsätze/Löschungen, die Wörterbücher für nicht optimiert)
  2. Die Liste ist ziemlich groß (sonst Overhead des Wörterbuchs ist sinnlos).

Wenn die oben sind für Ihre Situation ist nicht wahr, benutzen Sie einfach Any():

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

Diese durch die Liste aufzählen wird, bis es eine Übereinstimmung findet, oder bis das Ende erreicht ist.

+0

Die Verwendung eines Prädikats Delegat für die list.exists ist eine andere Lösung finden unten, aber wenn Sie riesige Listen und Schlüsselwert mit einem Wörterbuch haben, wird viel schneller sein, da es eine Hash-Tabelle ist! Enjoy – Doug

39

Wenn es wartbar diese zwei Eigenschaften zu verwenden, könnten Sie:

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

Ein weiterer Punkt ist zu erwähnen, dass Sie, dass Ihre Gleichheit Funktion erwarten, wie Sie ist sicherzustellen, sollte. Sie sollten die equals-Methode überschreiben, um festzulegen, welche Eigenschaften Ihres Objekts übereinstimmen müssen, damit zwei Instanzen als gleich betrachtet werden.

Dann können Sie einfach tun mylist.contains (Artikel)

6

Sind Sie sicher, dass Sie in diesem Fall eine Liste benötigen? Wenn Sie die Liste mit vielen Elementen auffüllen, leidet die Leistung unter myList.Contains oder myList.Any; die Laufzeit wird quadratisch sein. Vielleicht möchten Sie eine bessere Datenstruktur in Betracht ziehen.Zum Beispiel

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 eine HashSet auf folgende Weise verwenden:

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

Natürlich, wenn diese Definition der Gleichheit für MyClass ‚universal‘ ist, müssen Sie schreiben keine IEqualityComparer Implementierung ; Sie könnten GetHashCode und Equals in der Klasse selbst überschreiben.

+0

Ja, Bool für V war mein Favorit. Vor nicht allzu langer Zeit (etwa 3 Wochen) war HashSet für mich nicht verfügbar, weil ich an 2.0-Code arbeitete, und ich ließ die Mono-Implementierung von HashSet fallen, weil es so verdammt nützlich ist :) –

3

Edit: Ich hatte die erste:


Was ist mit dem Wörterbuch Lösung unelegant ist. Es scheint mir vollkommen elegant zu sein, zumal Sie nur den Vergleicher 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 spätere Operationen eine Indizierung erforderten, würde ich eine Liste daraus erstellen, wenn das Hinzufügen abgeschlossen war, ansonsten benutze einfach das Hashset.

+0

Ich würde das 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

3

Hier ist eine schnelle Konsole App, um das Konzept zur Lösung Ihres Problems darzustellen.

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 Sie!

37

Verwenden Sie einfach Contains Methode. Beachten Sie, dass es auf der Gleichheit Funktion arbeitet nach Equals

bool alreadyExist = list.Contains(item); 
+3

Dies funktionierte nicht für mich, es hat immer gesagt, dass es nicht existiert – Si8

+1

@ Si8 Wenn Sie Objekte zu vergleichen versuchen, müssen Sie sicher sein, dass die IEquatable .Equals-Implementierung ordnungsgemäß für den Typ Ihres Objekts implementiert ist. Andernfalls werden Sie den Objektinhalt nicht vergleichen. Siehe den Link Enthält Ahmad für ein Beispiel, wie dies implementiert werden kann. –

0

Einfach, aber es funktioniert

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

oder

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

Die zweite Option wird bereits von Ahmads Antwort abgedeckt –

Verwandte Themen