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();
我已经试着把循环全部移除,但也不起作用。
什么应该是最好的方法来实现这个更快。
我建议:使用HashSet
,等待ToList
和GroupBy
。
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
两个建议:
- 不物化文件
.ToList()
,即不等待所有文件被检索 - 将
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);
}
}