c# - System.Linq.Enumerable+WhereSelectArrayIterator 与 List 上的 IEnumerable.Except()
问题描述
也许我在这里遗漏了细节,但我希望 IEnumerable.Except() 可以在 Enumerables 上工作,而不是具体地转换为集合。
让我用一个简单的例子来解释一下:我有一个目录中的文件列表,我想排除以某个字符串开头的文件。
var allfiles = Directory.GetFiles(@"C:\test\").Select(f => new FileInfo(f));
获得匹配和不匹配的文件将是识别两个集合之一,然后在完整列表中添加 .Except()-ing 的问题,对吧?
var matching = allfiles.Where(f => f.Name.StartsWith("TOKEN"));
和
var notmatching = allfiles.Except(matching, new FileComparer());
其中 FileComparer() 是比较两个文件的完整路径的类。
好吧,除非我将这三个集合都转换为 List,否则最后一个不匹配的变量仍然会在匹配集合上的 I .Except() 之后给我完整的文件列表。要清楚:
var allfiles = Directory.GetFiles(@"C:\test\").Select(f => new FileInfo(f));
var matching = allfiles.Where(f => f.Name.StartsWith("TOKEN"));
var notmatching = allfiles.Except(matching, new FileComparer());
不排除,而
var allfiles = Directory.GetFiles(@"C:\test\").Select(f => new FileInfo(f)).ToList();
var matching = allfiles.Where(f => f.Name.StartsWith("TOKEN")).ToList();
var notmatching = allfiles.Except(matching, new FileComparer()).ToList();
实际上做了锡上所说的。我在这里想念什么?我不明白为什么 LINQ 不操作当前未转换为列表的集合。
例如,在第一种情况下甚至不会调用 FileComparer。
internal class FileComparer : IEqualityComparer<FileInfo>
{
public bool Equals(FileInfo x, FileInfo y)
{
return x == null ? y == null : (x.Name.Equals(y.Name, StringComparison.OrdinalIgnoreCase) && x.Length == y.Length);
}
public int GetHashCode(FileInfo obj)
{
return obj.GetHashCode();
}
}
解决方案
两者之间的区别在于,如果没有ToList
,延迟allfiles
查询会执行两次,产生的不同实例FileInfo
不会通过引用相等。
您的FileComparer
实现GetHashCode
不正确,因为它只是返回对象的基于引用的哈希码FileInfo
(它本身不会覆盖GetHashCode
)。
实现需要确保如果该
Equals(T, T)
方法返回true
两个对象x
和y
,则该方法返回的值GetHashCode(T)
必须x
等于返回的值y
。
解决方案是GetHashCode
基于与以下相同的相等定义来实现Equals
:
public int GetHashCode(FileInfo obj)
{
return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name);
}
推荐阅读
- sql - 按类别加入
- python - Is there a way to count the number of Changes that occur in a column and create a new count column based on that?
- python - 使用 pandas 的 one-hot 编码将虚拟变量列转换为 int
- python - 无法为 numpy 数据绘制图表得到空白图
- azure - 动态指定blob输出路径
- r - 绘图编码 R
- css - 我似乎找不到如何将我的 mp4 文件添加为标题而不是图片
- swift - 将字符串与 UIStepper 一起使用 - Swift
- r - 本地连接的一维自动编码器
- laravel - Laravel 6:如何覆盖 sendPasswordResetNotification 函数