注意:使用LINQ连接解决了这个问题。
如果目标列表中存在列表值,我需要比较“源列表”中的列表值,如果是,则将其保存到第三个列表中。
我编写的代码确实起作用,但是由于“源列表”中有3万个项目,因此花了很多时间,并且将每个项目的值与目标列表中的1500万个目标值进行比较,这花费了很多时间。因为它每次都会遍历整个列表(30k * 1500万次)
请参阅代码,该代码显然不是最佳方法,但是可以完成工作。
// The below code will generate the lists from CSV file
The lists are below for sample
**Source List**
FileId FilePath FileChecksum
1 somepath A check1
2 somepath AA check2
3 somepath AAB check3
4 somepath B check4
5 somepath BB check5
**Destination List**
StepId StatusID JobId ProjectId FileId FilePath
5 6 4 2091 577206853 somepath A
5 6 4 2092 577206853 somepath AA
5 6 4 2093 577206853 somepath AAA
5 6 4 2094 577206853 somepath AB
5 6 4 2095 577206853 somepath A
5 6 4 2096 577206853 somepath B
5 6 4 2097 577206853 somepath BB
List<Source> SourceList = File.ReadAllLines(@"D:\source.csv").Skip(1).Select(v => Source.SourceFromCSv(v)).ToList();
List<Destination> DestinationList = File.ReadAllLines(@"D:\Destination.csv").Skip(1).Select(d => Destination.FromDestinationCSV(d)).ToList();
//This will compare and create a new list
var result1 =
from s in SourceList
from d in DestinationList
where (d.FilePath.ToLower() == s.FilePath.ToLower())
select (d.StepId + "," + d.StatusId + "," + d.JobId + "," +
d.ProjectId + "," + d.FileId + "," + d.FilePath + "," +
s.FileChecksum);
Expected Result:
StepId StatusID JobId ProjectId FileId FilePath FileChecksum
5 6 4 2091 577206853 somepath A check1
5 6 4 2092 577206853 somepath AA check2
5 6 4 2095 577206853 somepath A check1
5 6 4 2096 577206853 somepath B check4
5 6 4 2097 577206853 somepath BB check5
答案 0 :(得分:3)
您可以对两个列表进行排序,然后逐行进行比较。 算法复杂度为O(n log n + n)。
将数据A的第一行与数据B的第一行进行比较,然后增加“更大”行上指针的索引。 如果数据A具有8,数据B具有7和9,则一旦达到9,您就会知道数据B中不存在8。
您应该以最大可能的索引开始比较。这样,如果列表确实是子列表,则可以快速终止。
答案 1 :(得分:1)
您可以反过来做。无需选择3万个源条目中的一个,就可以遍历3000万个条目。然后,如果您找到了所有3万条条目,或者在最坏的情况下,是在找到3000万条条目之后,就可以停止。那仍然比30K * 15M好。
答案 2 :(得分:1)
是的,如果您不需要列表的所有功能,将基本类型设置为HashSet<T>
会大大改善查找。您的自定义类型可能需要实现适当的GetHashCode()
函数,以进一步提高查找速度。
请参阅:
不要调用new HashSet(query.ToList())
,而是在实例化列表query.ToHashSet()
时直接转换为哈希集,可以选择传入Equal比较器,如下所示:
除了自定义GetHashCode
的实现之外,您还可以实现自定义IEqualityComparer
来处理诸如特定字段构成平等规则的特定情况,例如您的情况。如今,Visual Studio和Resharper提供了built-in refactor to generate a good implementation of GetHashCode
and Equals
。
请参阅:
然后您可以使用IntersectWith
在一次调用中获取两组中的所有项目:
请参阅:
创建一个特殊的对象,您可以将Source
和Destination
都转换为对象,或者给它们提供相同的基类将允许这样做。
您也可以使用IDictionary<Key, Value>
并将密钥设为Item.FilePath.ToLower()
,与上述相同。这将允许运行时使用字符串的GetHashCode
检查项目是否存在于其他列表中,该字符串在默认情况下进行了高度优化。
答案 3 :(得分:1)
var query = from s in SourceList
join d in DestinationList on
s.FilePath.ToLower().TrimEnd() equals d.FilePath.ToLower().TrimEnd()
select (d.StepId + "," + d.StatusId + "," + d.JobId + "," +d.ProjectId + "," + d.FileId + "," + d.FilePath + "," + s.FileChecksum);
LINQ join在不到5秒的时间内完成了同一件事。
答案 4 :(得分:0)
原则上您要做的就是将文件校验和附加到目标列表的末尾。
在源列表之外创建哈希或字典,然后新列表如下所示。
//create dictionary SourceDictionary<string,string> with key = filepath.tolower and value = checksum
var newList = DestinationList.select(d => $"{d.thing1},{d.thingN}" + SourceDictionary[d.filename.tolower()])
应该更快