【问题标题】:Compare files in List<FileInfo> using LINQ C#使用 LINQ C# 比较 List<FileInfo> 中的文件
【发布时间】:2014-11-25 17:26:39
【问题描述】:

我有 2 个文件集合为 List&lt;FileInfo&gt;。我目前正在使用 2 x foreach 循环遍历每个集合并匹配文件(如下所示)。有没有更快的方法在 LINQ 和.RemoveAt 中找到。

  • 我需要匹配的文件名和文件长度。

            var sdinfo = new DirectoryInfo(srcPath);
            var ddinfo = new DirectoryInfo(dstPath);
    
            var sFiles = new List<FileInfo>(sdinfo.GetFiles("*", SearchOption.AllDirectories));
            var dFiles = new List<FileInfo>(ddinfo.GetFiles("*", SearchOption.AllDirectories));
    
            foreach (var sFile in sFiles)
            {
                bool foundFile = false;
                int i = 0;
    
                foreach (var dFile in dFiles)
                {
                    if (sFile.Name == dFile.Name && sFile.Length == dFile.Length)
                    {
                        foundFile = true;
                        dFiles.RemoveAt(i);
                    }
                    i += 1;
                }
            }
    

干杯。

【问题讨论】:

  • 我假设您的示例代码中有错字。 sdinfo 和 ddinfo 都使用 srcPath。见第 1 行和第 2 行
  • 是的,那是 O 型。好地方,加油。已编辑。

标签: c# linq list file compare


【解决方案1】:

您可以使用Enumerable.Except&lt;TSource&gt; 方法:

private class FileInfoComparer : IEqualityComparer<FileInfo>
{
    public bool Equals(FileInfo x, FileInfo y)
    {
        return x == null ? y == null : (x.Name.Equals(y.Name, StringComparison.CurrentCultureIgnoreCase) && x.Length == y.Length);
    }

    public int GetHashCode(FileInfo obj)
    {
        return obj.GetHashCode();
    }
}

sFiles = sFiles.Except(dFiles, new FileInfoComparer()).ToList();

在上面的示例中,您从sFiles 中获取了dFiles 中不存在的所有文件。

【讨论】:

  • OP 要求提供比两个 for 循环更快的解决方案。 LINQ 是否有针对 except() 的不同算法?我意识到这是更少的代码行。我对性能很好奇。
  • @KC-NH Except 方法使用Set 类(哈希集的内部实现):LINQ source
【解决方案2】:

首先,如果执行此代码将引发异常,因为您在迭代枚举(dFiles)时对其进行了修改。这很容易通过使用ToList() method 来解决,但是为了复制枚举。这也会有一个问题,因为无论删除如何都会增加索引,这也可能导致错误 - 口语中的 off-by-one-exception。

如果您担心速度,请不要担心。 Linq 使用使用 foreach 和 yield 返回的方法,并且大部分在来自Reference Source 的源代码中可见。

如果您想让代码更易于阅读,那么这就是 Linq 有用的地方。其中之一是.Join() Method

foreach(var fileToRemove in sFiles.Join(dFiles, s => s, d => d, (s, d) => s).ToArray())
    dFiles.Remove(fileToRemove);

假设你之后正在迭代 dList,你也可以使用.Except(...) Method

var files = sdinfo.GetFiles("*", SearchOption.AllDirectories)
    .Except(ddinfo.GetFiles("*", SearchOption.AllDirectories));

最后,如果你需要 KEEP sFiles,下面的代码将它们包装在一起

List<string> sFiles, dFiles;
dFiles = ddinfo.GetFiles("*", SearchOption.AllDirectories)
    .Except(sFiles = sdinfo.GetFiles("*", SearchOption.AllDirectories));

【讨论】:

  • 这看起来很有用。基本上,如果有一个不匹配或丢失,我会在该方法上返回 false。
【解决方案3】:

如果你想用空间换时间,你可以构建一个包含一个列表的哈希集,并在哈希集中查找另一个列表的每个元素。查找是 O(1) 而循环是 O(n)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多