web-dev-qa-db-fra.com

comment vérifier si l'objet existe déjà dans une liste

J'ai une liste

  List<MyObject> myList

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

alors avant de faire ceci:

 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 l'appariement de deux propriétés.

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

la seule solution que j'ai imaginée était de passer d'une liste à un dictionnaire et de transformer la clé en une chaîne concaténée des propriétés (cela semble un peu peu élégant)

d'autres solutions plus propres utilisant list, LINQ ou autre chose?

70
leora

Cela dépend des besoins de la situation spécifique. Par exemple, l’approche par dictionnaire serait très bien supposée:

  1. La liste est relativement stable (peu d'insertions/suppressions pour lesquelles les dictionnaires ne sont pas optimisés)
  2. La liste est assez longue (sinon la surcharge du dictionnaire est inutile).

Si ce qui précède ne correspond pas à votre situation, utilisez simplement Any() :

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

Cela énumèrera la liste jusqu'à ce qu'elle trouve une correspondance ou jusqu'à la fin.

113
Rex M

Utilisez simplement Contains method. Notez que cela fonctionne sur la base de la fonction d'égalité Equals 

bool alreadyExist = list.Contains(item);
60
Ahmad

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

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

Êtes-vous sûr d'avoir besoin d'une liste dans ce cas? Si vous remplissez la liste avec de nombreux éléments, les performances seront affectées par myList.Contains ou myList.Any; le temps d'exécution sera quadratique. Vous voudrez peut-être 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 hachage 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 d'égalité pour MyClass est 'universelle', vous n'avez pas besoin d'écrire une implémentation IEqualityComparer; vous pouvez simplement remplacer GetHashCode et Equals dans la classe elle-même.

6
Ani

Un autre point à mentionner est que vous devez vous assurer que votre fonction d’égalité est conforme à vos attentes. Vous devez substituer la méthode equals pour définir les propriétés de votre objet qui doivent correspondre pour que deux instances soient considérées comme égales.

Ensuite, vous pouvez simplement faire Mylist.contains (item)

Edit: j'avais d'abord dit:


Qu'y a-t-il d'inélégant dans la solution de dictionnaire? Cela me semble tout à fait élégant, d'autant plus qu'il suffit de définir le comparateur dans la création du dictionnaire.


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

Par conséquent, je voudrais utiliser un HashSet. Si des opérations ultérieures nécessitaient l'indexation, je créerais une liste à la fin de l'ajout, sinon, utilisez simplement le hashset.

3
Jon Hanna

Voici une application de console rapide pour décrire le concept de la résolution de 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]);
                }
            }
        }
    }
}

Prendre plaisir!

3
Doug

Simple mais ça marche

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

ou

 if (!MyList.Contains(nextObject))
    MyList.Add(nextObject);
0
Opt Prutal