比较包含大量对象的两个列表(第 3 部分) "those objects have different type"



如何加快这个 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 解决方案太慢时,通常会发生这种情况。

相关内容

最新更新