Вопрос о сравнении 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);
    }
}