c# – 我有一个非高效的方法,我怎样才能提高它的效率?

我有一个简单的方法来比较FileInfo对象的数组与文件名列表,以检查已经处理了哪些文件.然后返回未处理的列表.

此方法的循环迭代大约250,000个FileInfo对象.这需要花费大量的时间来参加比赛.

效率低下显然是对processedFiles集合的Contains方法调用.

首先,我如何检查以确保我对原因的怀疑是肯定的;其次,我如何改进方法以加快处理速度?

public static List<FileInfo> GetUnprocessedFiles(FileInfo[] allFiles, List<string> processedFiles)
{
List<FileInfo> unprocessedFiles = new List<FileInfo>();
foreach (FileInfo fileInfo in allFiles)
{
    if (!processedFiles.Contains(fileInfo.Name))
    {
        unprocessedFiles.Add(fileInfo);
    }
    }
    return unprocessedFiles;
}
最佳答案
List< T>的Contains方法以线性时间运行,因为它可能必须枚举整个列表以证明项目的存在/不存在.我建议你使用aHashSet< string>或类似的. A HashSet<T>的Contains方法设计为在恒定的O(1)时间内运行,即它不应该取决于集合中的项目数.

这个小的改变应该使整个方法在线性时间内运行:

public static List<FileInfo> GetUnprocessedFiles(FileInfo[] allFiles, 
                                         List<string> processedFiles)
{
   List<FileInfo> unprocessedFiles = new List<FileInfo>();
   HashSet<string> processedFileSet = new HashSet<string>(processedFiles);

   foreach (FileInfo fileInfo in allFiles)
   {
       if (!processedFileSet.Contains(fileInfo.Name))
       {
           unprocessedFiles.Add(fileInfo);
       }
    }

   return unprocessedFiles;
}

如果可能的话,我会建议3项改进:

>为了提高效率,将处理后的文件存储在源的集合中,以便该方法采用ISet< T>.作为参数.这样,您不必每次都重建该集合.
>尽量不要以这种方式混合和匹配同一实体(字符串和FileInfo)的不同表示.选择一个并继续使用它.
>您可能还需要考虑HashSet< T> .ExceptWith方法而不是自己进行循环.请记住,这将改变集合.

如果您可以使用LINQ,并且您可以在每次调用时建立一个集合,这是另一种方式:

public static IEnumerable<string> GetUnprocessedFiles
 (IEnumerable<string> allFiles, IEnumerable<string> processedFiles)
{
  // null-checks here
  return allFiles.Except(processedFiles);     
}

转载注明原文:c# – 我有一个非高效的方法,我怎样才能提高它的效率? - 代码日志