2010-08-08 3 views
53

У меня есть списоккак проверить, если объект уже существует в списке

List<MyObject> myList 

и я добавлять элементы в список, и я хочу, чтобы проверить, что этот объект уже находится в списке.

так, прежде чем я это сделать:

myList.Add(nextObject); 

я хочу увидеть, если nextObject уже в списке.

объект «MyObject» имеет ряд свойств, но сравнение основано на сопоставлении по двум свойствам.

, что это лучший способ сделать проверку, прежде чем я добавить новый «MyObject» в Thsi список «MyObject» S

единственное решение я придумал было изменить из списка словаря и их сделайте ключ конкатенированной строкой свойств (это кажется немного неэлегантным)

любые другие решения для очистки, используя список или LINQ или что-то еще?

ответ

96

Это зависит от потребностей конкретной ситуации. Например, словарь подход неплохо было бы при условии:

  1. Список является относительно стабильным (не много вставок/удалений, которые словари не оптимизированы для)
  2. список довольно большой (в противном случае служебные данные словаря бессмысленны).

Если выше не относится к вашей ситуации, просто используйте Any():

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

Это будет перечислять по списку, пока не найдет совпадение, или пока он не дойдет до конца.

+0

Использование предиката делегата для list.exists другое решение см ниже, но если у вас есть огромные списки и значение ключа со словарем, это будет намного быстрее, так как это хеш-таблица! Наслаждайтесь – Doug

39

Если это ремонтопригодно использовать эти 2 свойство, вы можете:

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

Еще один момент упомянуть о том, что вы должны убедиться, что ваша функция равенства, как вы ожидаете. Вы должны переопределить метод equals, чтобы настроить, какие свойства вашего объекта должны совпадать для двух экземпляров, которые считаются равными.

Тогда вы можете просто сделать mylist.contains (пункт)

6

Вы уверены, что вам нужен список в этом случае? Если вы заполняете список множеством предметов, производительность будет страдать с myList.Contains или myList.Any; время выполнения будет квадратичным. Возможно, вы захотите рассмотреть возможность использования лучшей структуры данных.Например,

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

Вы можете использовать HashSet следующим образом:

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

Конечно, если это определение равенства для MyClass является «универсальным», вам не нужно писать IEqualityComparer реализации ; вы могли бы просто переопределить GetHashCode и Equals в самом классе.

+0

Да, bool для V был моим любимым. Если уж на то пошло, это было не так давно (ах, около 3 недель), что HashSet не был доступен мне, потому что я работал над кодом 2.0, и я отказался от реализации HashSet в Mono, потому что это так чертовски полезно :) –

3

Edit: я первый сказал:


Что безвкусный о словаре решения. Мне кажется, это очень элегантно, потому что вам нужно установить компаратора при создании словаря.


Конечно, хотя это нецелесообразно использовать что-то в качестве ключа, когда это также значение.

Поэтому я бы использовал HashSet. Если последующие операции потребовали индексации, я бы создал список из него, когда было добавлено добавление, иначе просто используйте hashset.

+0

Я бы использовал это только в том случае, если список объектов был огромным с его хэш-таблицы, и они отлично подходят для быстрого поиска. – Doug

3

Это быстрое консольное приложение, чтобы отобразить концепцию решения вашей проблемы.

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

Наслаждайтесь!

37

Просто используйте Contains способ. Обратите внимание, что она работает на основе функции равенства Equals

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

Это не сработало для меня, оно всегда говорило, что его не существует – Si8

+1

@ Si8 Если вы пытаетесь сравнить объекты, вы должны быть уверены, что реализация IEquatable .Equals корректно реализована для вашего типа объекта. В противном случае вы не будете сравнивать содержимое объекта. См. Ссылку Содержит Ахмад для примера того, как это реализовать. –

0

Простой, но это работает

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

или

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

Второй вариант уже включен в ответ Ахмадом –

Смежные вопросы