Использование Linq, кроме как не работает, как я думал

List1 содержит элементы { A, B } и List2 содержит элементы { A, B, C }.

Мне нужно вернуть { C } , Когда я использую, кроме расширения Linq. Вместо этого я получаю { A, B}, и если я переверну списки в своем выражении, результат будет { A, B, C }.

Я неправильно понимаю смысл Except? Есть ли еще одно расширение, которое я не вижу, чтобы использовать?

Я просмотрел и попробовал несколько разных сообщений по этому вопросу без успеха до сих пор.

var except = List1.Except(List2); //This is the line I have thus far

EDIT: Да, я сравнивал простые объекты. Я никогда не использовал IEqualityComparer, было интересно узнать об этом.

спасибо всем за помощь. Проблема заключается не в применении компаратора. Связанное сообщение в блоге и пример ниже, где полезно.

4 ответов


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

можно реализовать IEqualityComparer<T> и отправить его в качестве параметра кроме()


вы просто перепутали порядок аргументов. Я вижу, где возникла эта путаница, потому что официальная документация не так полезно, как могло бы быть:

создает разность двух последовательностей с помощью компаратора равенства по умолчанию для сравнения значений.

Если вы не разбираетесь в теории множеств, может быть неясно, что установить разницу на самом деле-это не просто то, что отличается между множествами. В реальность, Except возвращает список элементов в первом наборе, которых нет во втором наборе.

попробуйте это:

var except = List2.Except(List1); // { C }

Так Просто для полноты...

// Except gives you the items in the first set but not the second
    var InList1ButNotList2 = List1.Except(List2);
    var InList2ButNotList1 = List2.Except(List1);
// Intersect gives you the items that are common to both lists    
    var InBothLists = List1.Intersect(List2);

Edit: поскольку ваши списки содержат объекты, вам нужно передать IEqualityComparer для вашего класса... Вот как будет выглядеть ваше исключение с образцом IEqualityComparer на основе составленных объектов... :)

// Except gives you the items in the first set but not the second
        var equalityComparer = new MyClassEqualityComparer();
        var InList1ButNotList2 = List1.Except(List2, equalityComparer);
        var InList2ButNotList1 = List2.Except(List1, equalityComparer);
// Intersect gives you the items that are common to both lists    
        var InBothLists = List1.Intersect(List2);

public class MyClass
{
    public int i;
    public int j;
}

class MyClassEqualityComparer : IEqualityComparer<MyClass>
{
    public bool Equals(MyClass x, MyClass y)
    {
        return x.i == y.i &&
               x.j == y.j;
    }

    public int GetHashCode(MyClass obj)
    {
        unchecked
        {
            if (obj == null)
                return 0;
            int hashCode = obj.i.GetHashCode();
            hashCode = (hashCode * 397) ^ obj.i.GetHashCode();
            return hashCode;
        }
    }
}

как раз для Ref: Я хотел сравнить USB-накопители, подключенные и доступные для системы.

Итак, это класс, который реализует интерфейс IEqualityComparer

public class DriveInfoEqualityComparer : IEqualityComparer<DriveInfo>
{
    public bool Equals(DriveInfo x, DriveInfo y)
    {
        if (object.ReferenceEquals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        // compare with Drive Level
        return x.VolumeLabel.Equals(y.VolumeLabel);
    }

    public int GetHashCode(DriveInfo obj)
    {
        return obj.VolumeLabel.GetHashCode();
    }
}

и вы можете использовать его в таком виде

var newDeviceLst = DriveInfo.GetDrives()
                            .ToList()
                            .Except(inMemoryDrives, new DriveInfoEqualityComparer())
                            .ToList();