Вопрос о сравнении List <T>
У меня есть два списка:
List<comparerobj> list_c = new List<comparerobj>();
List<comparerobj> list_b = new List<comparerobj>();
Я как-то заполняю списки
то я пытаюсь найти элементы в list_b, которые list_c не содержит:
foreach (comparerobj b in list_b)
{
bool lc = !list_c.Contains(b);
if (lc != true)
{
data.Add(b);
}
}
но для любого b я получаю, что lc = true. что я делаю неправильно?
Ответы
Ответ 1
Как сравниваются ваши объекты? По умолчанию .NET Framework сравнивает объекты по ссылкам. Например, если вы создаете следующий класс:
class A
{
string Name { get; set; }
}
и следующий код
A a1 = new A() { Name = "a" };
A a2 = new A() { Name = "a" };
то вы обнаружите, что эти объекты разные.
Вам необходимо переопределить метод Equals
для .NET Framework, чтобы обработать вышеуказанные объекты как равные.
Ответ 2
Это любопытно, но потерять временный bool. Это не недвусмысленно, и это сбивает с толку:
foreach (comparerobj b in list_b)
{
if (list_c.Contains(b))
{
data.Add(b);
}
}
Теперь, когда вы видите упрощенную логику, ясно, что вы добавляете только те элементы, которые находятся в обоих списках. Здесь может быть полезен один минус:
foreach (comparerobj b in list_b)
{
if (!list_c.Contains(b))
{
data.Add(b);
}
}
Ответ 3
Если вы используете .NET 3.5, это просто:
list_b.Except(list_c);
Если это еще не правильно вычисляет равенство, второй параметр Except()
- это IEqualityComparer<T>
, который затем можно использовать для сравнения ваши объекты, как вы пожелаете, или вы можете просто переопределить Equals()
для своего compareobjs
.
Если вы хотите поместить значения в новый список (который я собираю из переменной data
), вы можете просто сделать это:
var data = list_b.Except(list_c).ToList();
Edit:
Вы упомянули, что это не работает, и это, вероятно, потому, что вы не переопределили Equals()
и GetHashCode()
, чтобы определить равенство значений. Самый простой способ заставить ваш пример работать - использовать интерфейс IEquatable<T>
на CompareObj
:
public class CompareObj : IEquatable<CompareObj>
{
public bool Equals(CompareObj other)
{
// example equality, customize for your object
return (this.ExampleValue.Equals(other.ExampleValue));
}
}
Более подробную информацию можно найти в MSDN: http://blogs.msdn.com/csharpfaq/archive/2009/03/25/how-to-use-linq-methods-to-compare-objects-of-custom-types.aspx
Ответ 4
Вы дважды инвертируете логическое значение. После первой строки, когда вы делаете !list_...
и один раз на втором, когда вы делаете lc != true
.
Попробуйте это вместо:
bool itemExistsInC = list_c.Contains(b);
if (!itemExistsInC){
Ответ 5
Вы используете! оператора дважды.
Кроме того, в этом контексте вам не нужно явно обрабатывать bool.
Попробуйте следующее:
foreach (object b in list_b)
{
if (!list_c.Contains(b))
{
data.Add(b);
}
}
Ответ 6
Использование linq
list_b.Except(list_c).ToList().ForEach(data.Add);
но для любого b я получаю, что lc = правда. что я делаю неправильно?
Одно или несколько из следующих действий:
- Ваши наборы совершенно разные.
- compareerobj необходимо перегрузить метод Equals()
- Используемая вами логика вводит в заблуждение и не работает должным образом.
Если вам нужны только элементы в list_b, которых нет в списке_c:
foreach (comparerobj b in list_b)
{
if (!list_c.Contains(b))
{
data.Add(b);
}
}