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?
Cela dépend des besoins de la situation spécifique. Par exemple, l’approche par dictionnaire serait très bien supposée:
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.
Utilisez simplement Contains method. Notez que cela fonctionne sur la base de la fonction d'égalité Equals
bool alreadyExist = list.Contains(item);
S'il est maintenable d'utiliser ces 2 propriétés, vous pouvez:
bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");
Ê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.
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.
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!
Simple mais ça marche
MyList.Remove(nextObject)
MyList.Add(nextObject)
ou
if (!MyList.Contains(nextObject))
MyList.Add(nextObject);