2010-08-08 31 views
53

Tengo una listacómo comprobar si el objeto ya existe en una lista

List<MyObject> myList 

y yo estoy añadiendo elementos a una lista y quiero comprobar si ese objeto ya está en la lista.

Así que antes de hacer esto:

myList.Add(nextObject); 

quiero ver si nextObject ya está en la lista.

el objeto "MyObject" tiene una serie de propiedades, pero la comparación se basa en la coincidencia de dos propiedades.

¿cuál es la mejor manera de hacer una verificación antes de agregar un nuevo "MiObjeto" a thsi lista de "MiObjeto" s

la única solución se me ocurrió fue cambiar de una lista a un diccionario y les hacer que la clave sea una cadena concatenada de las propiedades (esto parece un poco poco elegante)

¿Alguna otra solución de limpieza usando list o LINQ o alguna otra cosa?

Respuesta

96

Depende de las necesidades de la situación específica. Por ejemplo, el enfoque diccionario sería bastante bueno suponiendo:

  1. La lista es relativamente estable (no un montón de inserciones/deleciones, que los diccionarios no están optimizados para)
  2. la lista es bastante grande (de lo contrario la sobrecarga del diccionario no tiene sentido).

Si lo anterior no son ciertas para su situación, sólo tiene que utilizar Any():

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

Esto enumerar la lista hasta que encuentre una coincidencia, o hasta que llegue al final.

+0

El uso de un delegado predicado por los list.exists es otra solución ver a continuación, pero si tiene enormes listas y valores clave con un diccionario, ¡será mucho más rápido ya que es una tabla hash! Disfruta – Doug

39

Si es mantenible a utilizar esos 2 propiedades, usted podría:

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

Otro punto a mencionar es que usted debe asegurarse de que su función es la igualdad de la forma esperada. Debe anular el método equals para configurar las propiedades de su objeto que deben coincidir para que dos instancias se consideren iguales.

continuación, sólo puede hacer mylist.contains (punto)

6

¿Seguro de que necesita una lista que en este caso? Si está completando la lista con muchos elementos, el rendimiento sufrirá con myList.Contains o myList.Any; el tiempo de ejecución será cuadrático. Es posible que desee considerar el uso de una mejor estructura de datos.Por ejemplo,

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

Se puede usar un HashSet de la siguiente manera:

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

Por supuesto, si esta definición de la igualdad para MyClass es 'universal', no necesita escribir una implementación IEqualityComparer ; podría simplemente anular GetHashCode y Equals en la clase misma.

+0

Sí, bool para V era mi favorito. Para el caso, no fue hace tanto tiempo (eh, alrededor de 3 semanas) que HashSet no estaba disponible para mí porque estaba trabajando en el código 2.0, y abandoné la implementación Mono de HashSet porque es muy útil :) –

3

Edit: había dicho primero:


¿Qué hay poco elegante sobre la solución diccionario. Me parece perfectamente elegante, especialmente porque solo necesita establecer el comparador en la creación del diccionario.


Sin embargo, es poco elegante usar algo como clave cuando también es el valor.

Por lo tanto, utilizaría un HashSet. Si las operaciones posteriores requerían indexación, crearía una lista cuando finalizara la adición; de lo contrario, simplemente use el hashset.

+0

Solo usaría esto si la lista de objetos fuese enorme ya que es una tabla hash y son excelentes para búsquedas rápidas. – Doug

3

Aquí hay una aplicación de consola rápida para describir el concepto de cómo resolver su problema.

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

Enjoy!

37

Simplemente use el método Contains. Tenga en cuenta que funciona basándose en la función de la igualdad Equals

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

Esto no funcionó para mí, siempre dijo que no existe – Si8

+1

@ Si8 Si está tratando de comparar objetos, debe asegurarse de que la implementación de IEtabletable .Equals se implemente correctamente para el tipo de su objeto. De lo contrario, no comparará el contenido del objeto. Vea el enlace contiene Ahmad indicado para un ejemplo de cómo implementar esto. –

0

simple pero funciona

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

o

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

La segunda opción ya está cubierta por la respuesta de Ahmad –

Cuestiones relacionadas