У меня есть список
List<MyObject> myList
, и я добавляю элементы в список, и я хочу проверить, есть ли этот объект уже в списке.
поэтому, прежде чем я сделаю это:
myList.Add(nextObject);
Я хочу посмотреть, есть ли следующий объект в списке.
Объект «MyObject» имеет ряд свойств, но сравнение основано на сопоставлении двух свойств.
Что является лучшим способом сделать проверку, прежде чем я добавлю новый «MyObject» в этот список «MyObject» s.
Единственное решение, которое я придумал, - это перейти от списка к словарю, а затем сделать ключ составной строкой свойств (это выглядит немного нелегко).
Любые другие более чистые решения, использующие list или LINQ. или что-то еще?
Это зависит от потребностей конкретной ситуации. Например, подход, основанный на словаре, будет вполне хорош, если:
Если вышеперечисленное не верно для вашей ситуации, просто используйте Any()
:
Item wonderIfItsPresent = ...
bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);'
Это перечислит весь список, пока не найдет совпадение, или пока не достигнет конца.
Еще один момент, о котором следует упомянуть, - это то, что вы должны убедиться, что ваша функция равенства соответствует вашим ожиданиям. Вы должны переопределить метод equals, чтобы указать, какие свойства вашего объекта должны совпадать, чтобы два экземпляра считались равными.
Тогда вы можете просто сделать mylist.contains (элемент)
Если эти 2 свойства можно поддерживать, вы можете:
bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");
Редактировать: Сначала я сказал:
Что неэлегантного в словарном решении. Мне это кажется совершенно элегантным, особенно потому, что вам нужно только установить компаратор при создании словаря.
Конечно, неэлегантно использовать что-то в качестве ключа, когда оно также является значением.
Поэтому я бы использовал HashSet. Если последующие операции потребовали индексации, я бы создал список из него после завершения добавления, в противном случае просто использовал бы хэш-набор.
Вы уверены, что в данном случае вам нужен список? Если вы заполняете список большим количеством элементов, производительность пострадает при использовании 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
в самом классе.
Вот быстрое консольное приложение, чтобы показать концепцию решения вашей проблемы.
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]);
}
}
}
}
}
Наслаждайтесь!