比较包含大量对象的两个列表(第 3 部分)“这些对象具有不同的类型”
本文关键字:对象 类型 包含大 两个 比较 列表 部分 | 更新日期: 2023-09-27 17:57:01
如何加快这个 linq 查询的速度?
这需要很长时间,当我在列表中放置很多对象时,会出现内存异常。
List<DirectoryInfo> directoriesThatWillBeCreated = new List<DirectoryInfo>();
// some code to fill the list
// ..
// ..
List<FileInfo> FilesThatWillBeCopied = new List<FileInfo>();
// some code to fill the list
//....
directoriesThatWillBeCreated = (from a in FilesThatWillBeCopied
from b in directoriesThatWillBeCreated
where a.FullName.Contains(b.FullName)
select b).ToList();
我希望我可以做一些像以前的解决方案一样的事情,但在处理不同类型的对象时我不知道该怎么做。我是否必须创建一个新类,然后将所有 FileInfo 和 DirectoryInfo 对象转换为该类,然后执行查询?此外,FileInfo 和 DirectoryInfo 类是密封的,我无法从它们继承,因此我将不得不创建一个新类,这将没有效率。至少这将比该查询更有效,因为该查询需要很长时间。
您可以做的一件事是将包含更改为 StartsWith。 如果匹配失败,StartsWith
会更快地失败。
directoriesThatWillBeCreated = (from a in FilesThatWillBeCopied
from b in directoriesThatWillBeCreated
where a.FullName.StartsWith(b.FullName)
select b).ToList();
但是,这不是一个完整的解决方案。如果FilesThatWillBeCopied
有 M 个项目,directoriesThatWillBeCreated
有 N 个元素,则查询将处理 MxN 字符串比较。
另一种选择
要尝试的另一种优化是,首先循环访问directoriesThatWillBeCreated
,然后选择与FilesThatWillBeCopied
中的任何FileInfo
匹配的优化。通过检查是否有任何匹配项,一旦找到匹配项,您就可以中断对文件的测试。可以这样完成:(警告,记事本代码如下)
directoriesThatWillBeCreated = directoryThatWillBeCreated
.Select(b => FilesThatWillBeCopied
.Any(a => a.FullName.StartsWith(b.FullName)));
它很慢,因为代码在每个文件的目录列表中进行线性搜索。试试这个:
var dirlist = FilesThatWillBeCopied
.Select(f => Directory.GetParent(f.FullName))
.GroupBy(d => d.FullName)
您可能需要稍微玩一下语法,但希望您能明白这一点。
我建议使用HashSet<DirectoryInfo>
进行比较,但不幸的是,DirectoryInfo
没有实现适当的相等比较,所以字符串必须这样做。 (另一种选择是实现你自己的IComparer<DirectoryInfo>
。此外,除非确定两个集合的大小写相同,否则应在名称上使用 StringComparer.InvariantCultureIgnoreCase
。
var dirs = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// fill dirs
var files = new List<FileInfo>();
// fill files
var result = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
foreach (var file in files)
{
var dir = file.Directory;
while (dir != null && !result.Contains(dir.FullName))
{
if (dirs.Contains(dir.FullName))
result.Add(dir.FullName);
dir = dir.Parent;
}
}
此解决方案根本不使用 LINQ,但当您追求性能并且最直接的 LINQ 解决方案太慢时,通常会发生这种情况。