使用Linq除了不像我想象的那样工作

本文关键字:工作 Linq 使用 | 更新日期: 2023-09-27 18:16:03

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

编辑:是的,我是比较简单的对象。我从未使用过IEqualityComparer,了解它很有趣。

谢谢大家的帮助。问题在于没有实现比较器。下面链接的博客文章和示例很有帮助。

使用Linq除了不像我想象的那样工作

如果您在列表中存储引用类型,则必须确保有一种方法来比较对象是否相等。否则,它们将通过比较来检查它们是否引用相同的地址。

您可以实现IEqualityComparer<T>并将其作为参数发送给Except()函数。这是一篇你可能会觉得有用的博客文章。

edit :原来的博客文章链接被打断了,已经被替换了

所以只是为了完整…

// 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);

编辑:因为你的列表包含对象,你需要在一个IEqualityComparer为你的类传递…下面是你的except将看起来像一个基于组成对象的示例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;
        }
    }
}

您只是混淆了参数的顺序。我知道为什么会出现这种混淆,因为官方文档并没有提供足够的帮助:

使用默认的相等比较器比较值,产生两个序列的集合差值。

除非你精通集合理论,否则你可能不清楚什么是集合差;它不仅仅是集合之间的不同。实际上,Except返回的是第一个集合中不在第二个集合中的元素列表。

试试这个:

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

编写一个自定义比较器似乎解决了这个问题,但我认为https://stackoverflow.com/a/12988312/10042740是一个更简单和优雅的解决方案。

它会覆盖对象定义类中的GetHashCode()和Equals()方法,然后默认比较器就会发挥它的魔力,而不会把额外的代码弄得乱七八糟。

仅供参考:我想比较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();