c#比较一个列表和另一个列表的一部分

本文关键字:列表 另一个 一部分 一个 比较 | 更新日期: 2023-09-27 18:11:58

我正在尝试从网站上删除不需要的图像。产品图片文件夹包含超过200000张图片。我有一个列表中不活跃的产品代码列表。我在另一个列表中有一个文件名列表。

List<string> lFileList = files.ToList();
List<string> lNotinfiles = new List<string>();
foreach (var s in lFileList)
{
   var s2 = (from s3 in lProductsList 
             where s.Contains(s3.cProductCode) 
             select s3.cProductCode).FirstOrDefault();
   if (s2 == null)
   {
      lNotinfiles.Add(s);
   }
}

这里的lProductsList是包含未使用的ProductCodes的列表。图像列表包含同一产品的多个图像,但图像名称包含产品代码(通常以_1开头,可能有_1,_2.jpg将在那里。

上面的代码工作,但它需要超过5分钟的单个文件夹获得Not in列表。我确实尝试了下面的方法,但花了15多分钟。

var s2 = (from s3 in lProductsList 
          where s.IndexOf(s3.cProductCode) >= 0 
          select s3.cProductCode).FirstOrDefault();

我已经试着把循环全部移除,但也不起作用。

什么应该是最好的方法来实现这个更快。

c#比较一个列表和另一个列表的一部分

我建议:使用HashSet,等待ToListGroupBy

HashSet +使用ToList

当前你的代码的时间复杂度为0 (n)2 -你迭代外部列表,并为每个项迭代内部列表的所有项。

lProductsList的类型从列表更改为包含代码的HashSet<string>。在HashSet中查找项目的次数为0 (1)(list为0 (n))。然后,当你迭代lFileList的每次次数以确定它们是否在lProductsList中时,它的时间复杂度将为o(n)而不是o(n)2。

这段代码将向您展示使用两个列表或使用列表和HashSet之间的时差:

var items = (new[] { "1", "2", "3","4","5","6","7","8","9","10" }).SelectMany(x => Enumerable.Repeat(x, 10000)).ToList();
var itemsToFilterOut = new List<string> { "1", "2", "3" };
var efficientItemsToFilterOut = new HashSet<string>(itemsToFilterOut);
var watch = System.Diagnostics.Stopwatch.StartNew();
var unwantedItems = items.Where(item => itemsToFilterOut.Contains(item)).ToList();
watch.Stop();
Console.WriteLine(watch.TotalMilliseconds);
watch = Stopwatch.StartNew();
var efficientUnwantedItems = items.Where(item => efficientItemsToFilterOut.Contains(item)).ToList();
watch.Stop();
Console.WriteLine(watch.TotalMilliseconds);

至于把它放在你的代码上下文中:

var notInUseItems = new HashSet(from item in lProductsList
                                select item.cProductCode);
//Notice that here I am not using the materialized `lFileList`
lNotinfiles = files.Where(item => !notInUseItems.Contains(item));

GroupBy

而且 -您说列表包含映射到同一键的多个项。过滤前使用GroupBy。检查此添加项的性能:

watch = Stopwatch.StartNew();
var moreEfficientUnwantedItems = items.GroupBy(item => item)
     .Where(group => efficientItemsToFilterOut.Contains(group.Key))
     .Select(group => group.Key);
watch.Stop();
Console.WriteLine(watch.TotalMilliseconds);

检查你的数据,分析重复的数量有多重要,如果需要的话,使用GroupBy

两个建议:

  1. 物化文件.ToList(),即不等待所有文件被检索
  2. NotInFiles组织为HashSet<String>,以获得更好的复杂性O(1)而不是O(N)

像这样:

  //TODO: you have to implement this 
  prtivate static String ExtractProductCode(string fileName) {
    int p = fileName.IndexOf('_');
    if (p >= 0)
      return fileName.SubString(0, p);
    else
      return fileName;  
  }

  HashSet<String> NotInFiles = new HashSet<String>(
    lNotinfiles, 
    StringComparer.OrdinalIgnoreCase); // file names are case insensitive

.

  var files = Directory 
    .EnumerateFiles(@"C:'MyPictures", "*.jpeg", SearchOption.AllDirectories)
    .Where(path => Path.GetFileNameWithoutExtension(path))
    .Select(path => ExtractProductCode(path))
    .Where(code => !NotInFiles.Contains(code))
    .ToList(); // if you want List materialization

您正在将您的(我假设)数组转换为列表,然后执行foreach直接在数组上使用for应该会使它至少快一点。

List<string> lNotinfiles = new List<string>();
            for(int i = 0; i < files.Count(); i++)
            foreach (var s in files)
             {
                var s2 = (from s3 in lProductsList where s.Contains(s3.cProductCode) select s3.cProductCode).FirstOrDefault();
                if (s2 == null)
                   {
                      lNotinfiles.Add(s);
                   }
             }