2010-08-08 7 views
53

J'ai une listecomment vérifier si l'objet existe déjà dans une liste

List<MyObject> myList 

et je suis d'ajouter des éléments à une liste et je veux vérifier si cet objet est déjà dans la liste.

donc avant que je fais:

myList.Add(nextObject); 

je veux voir si nextObject est déjà dans la liste.

l'objet "MyObject" a un certain nombre de propriétés, mais la comparaison est basée sur la correspondance sur deux propriétés.

quelle est la meilleure façon de faire une vérification avant d'ajouter un nouveau « MyObject » à thsi liste des « MyObject » s

la seule solution que je pensais jusqu'à était de passer d'une liste à un dictionnaire et les faire à la clé une chaîne concaténée des propriétés (cela semble un peu unelegant)

d'autres solutions de nettoyage en utilisant la liste ou LINQ ou autre chose?

Répondre

96

Cela dépend des besoins de la situation spécifique. Par exemple, l'approche dictionnaire serait tout à fait bonne supposer:

  1. La liste est relativement stable (pas beaucoup d'insertions/suppressions, qui dictionnaires ne sont pas optimisés pour)
  2. La liste est assez grand (sinon le les frais généraux du dictionnaire sont inutiles).

Si ce qui précède ne sont pas vraies pour votre situation, il suffit d'utiliser Any():

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

Cela énumérer la liste jusqu'à ce qu'il trouve une correspondance, ou jusqu'à ce qu'il atteigne la fin.

+0

L'utilisation d'un délégué de la base pour la List.exists est une autre solution voir ci-dessous, mais si vous avez d'énormes listes et la valeur clé avec un dictionnaire sera beaucoup plus rapide car c'est une table de hachage! Enjoy – Doug

39

S'il est maintenable d'utiliser ces 2 propriétés, vous pouvez:

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

Un autre point à mentionner est que vous devez vous assurer que votre fonction d'égalité est comme prévu. Vous devez remplacer la méthode equals pour définir quelles propriétés de votre objet doivent correspondre pour que deux instances soient considérées comme égales.

Ensuite, vous pouvez juste faire mylist.contains (ITEM)

6

Êtes-vous sûr que vous avez besoin d'une liste dans ce cas? Si vous remplissez la liste avec de nombreux éléments, les performances vont souffrir avec myList.Contains ou myList.Any; l'exécution sera quadratique. Vous pourriez envisager d'utiliser une meilleure structure de données.Par exemple,

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()); 
     } 
    } 

Vous pouvez utiliser un HashSet de la manière suivante:

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

Bien sûr, si cette définition de l'égalité pour MyClass est « universel », vous ne devez pas écrire une implémentation IEqualityComparer ; vous pouvez simplement remplacer GetHashCode et Equals dans la classe elle-même.

+0

Oui, bool pour V était mon préféré. D'ailleurs, il n'y a pas si longtemps (environ 3 semaines) que HashSet n'était pas disponible parce que je travaillais sur du code 2.0, et j'ai abandonné l'implémentation Mono de HashSet parce que c'est tellement utile :) –

3

Edit: j'avais d'abord dit:


Quelle est inélégant sur la solution dictionnaire. Cela me semble parfaitement élégant, d'autant plus que vous avez seulement besoin de mettre le comparateur dans la création du dictionnaire.


Bien sûr, il est inélégant d'utiliser quelque chose comme une clé quand c'est aussi la valeur.

Par conséquent j'utiliserais un HashSet. Si des opérations ultérieures nécessitaient une indexation, j'en créerais une liste quand l'ajout serait fait, sinon, utilisez simplement le hashset.

+0

Je ne l'utiliserais que si la liste des objets était énorme car c'est une table de hachage et ils sont parfaits pour les recherches rapides. – Doug

3

Voici une application de console rapide pour illustrer le concept de la façon de résoudre votre problème.

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]); 
       } 
      } 
     } 
    } 
} 

Profitez-en!

37

Il suffit d'utiliser la méthode Contains. Notez qu'il fonctionne selon la fonction d'égalité Equals

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

Cela n'a pas fonctionné pour moi, il a toujours dit qu'il n'existe pas – Si8

+1

@ Si8 Si vous essayez de comparer des objets, vous devez vous assurer que l'implémentation IEquatable .Equals est implémentée correctement pour le type de votre objet. Sinon, vous ne comparerez pas le contenu de l'objet. Voir le lien Contient Ahmad indiqué pour un exemple de la façon de l'implémenter. –

0

simple mais cela fonctionne

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

ou

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

La deuxième option est déjà couverte par la réponse d'Ahmad –

Questions connexes