使用 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<T>
并将其作为参数发送给Except() 函数。这是blog post,您可能会觉得有帮助。
编辑:original blog post link 已损坏并已在上面替换
【讨论】:
要明确的是,这是很久以前解决我的问题的解决方案,并且是一个可行的选择,具体取决于您的方案。 我有一个List<MyType>
,而MyType
实现了IEquatable<T>
。但是,当我使用 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 除了不像我想的那样工作的主要内容,如果未能解决你的问题,请参考以下文章
Clickhouse:runningAccumulate() 不像我预期的那样工作