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

Posted

技术标签:

【中文标题】使用 Linq 除了不像我想的那样工作【英文标题】:Using Linq Except not Working as I Thought 【发布时间】:2013-05-25 08:30:28 【问题描述】:

List1 包含项目 A, B List2 包含项目 A, B, C

当我使用除了 Linq 扩展时,我需要返回 C 。相反,我返回 A, B ,如果我在我的表达式中翻转列表,结果是 A, B, C

我是否误解了“除外”的意义?有没有其他我看不到的扩展程序?

到目前为止,我已经查看并尝试了许多关于此问题的不同帖子。

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

编辑:是的,我在比较简单的对象。我从未使用过IEqualityComparer,学习起来很有趣。

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

【问题讨论】:

这些列表中到底有什么? 您的商品的数据类型是什么。是一堂课吗?此链接可能对您有所帮助***.com/questions/1645891/… 目前它们是具有几个属性的简单对象。我会看看你的链接。 【参考方案1】:

您只是混淆了参数的顺序。我可以看到这种混淆出现在哪里,因为 official documentation 并没有它应有的帮助:

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

除非您精通集合论,否则可能不清楚 set difference 究竟是什么——这不仅仅是集合之间的不同之处。实际上,Except 返回第一个集合中不属于第二个集合的元素列表。

试试这个:

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

【讨论】:

如果更改列表顺序我得到 A, B, C 【参考方案2】:

所以只是为了完整性......

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

【讨论】:

InList1ButNotList2 给出的是 C, B, A ,这就是正在发生的事情。 @Schanckopotomus 啊……你的列表是对象,它们的属性是相等的,但对象的引用不相等对吗?【参考方案3】:

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

您可以实现IEqualityComparer&lt;T&gt; 并将其作为参数发送给Except() 函数。这是blog post,您可能会觉得有帮助。

编辑:original blog post link 已损坏并已在上面替换

【讨论】:

要明确的是,这是很久以前解决我的问题的解决方案,并且是一个可行的选择,具体取决于您的方案。 我有一个List&lt;MyType&gt;,而MyType 实现了IEquatable&lt;T&gt;。但是,当我使用 Except 方法时,我仍然得到 OP 所指的 A, B, C 。有什么问题? 文章的格式不是很好,真可惜。【参考方案4】:

仅供参考: 我想比较系统连接和可用的 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();

【讨论】:

【参考方案5】:

编写自定义比较器似乎确实可以解决问题,但我认为https://***.com/a/12988312/10042740 是一个更简单、更优雅的解决方案。

它会覆盖对象定义类中的 GetHashCode() 和 Equals() 方法,然后默认的比较器会发挥它的魔力,而不会造成额外的代码混乱。

【讨论】:

以上是关于使用 Linq 除了不像我想的那样工作的主要内容,如果未能解决你的问题,请参考以下文章

sleep() 不像我预期的那样工作

这个节点不像我想象的那样工作?

Clickhouse:runningAccumulate() 不像我预期的那样工作

我不能像我想的那样返回字符串切片。只通过最后一个

变形金刚 BartTokenizer::add_tokens() 不像我对后缀的预期那样工作

QUdpSocket 高速率消息读取