我有一个包含一些元素的列表,我想从另一个列表中删除元素。 如果某项的值Contain
(不等于)另一个列表中的值,则应将其删除。
其中一种方法是执行此操作:
var MyList = new List<string> { ... }
var ToRemove = new List<string> { ... }
MyList.RemoveAll(_ => ToRemove.Any(_.Contains));
有效...
但是,我有很多个列表(> 1百万个),并且由于可以对ToRemove进行排序,因此使用它来加快处理速度是很有意义的。
创建一个循环可以很容易地做到这一点,但是有一种方法可以对已排序的集合执行此操作?
更新:
在包含禁止列表的文本上进行20k次迭代后,我得到了:
禁止列表作为列表-> 00:00:07.1993364
禁止列表作为HashSet-> 00:00:07.9749997
多次运行后保持一致,因此哈希集较慢
答案 0 :(得分:1)
由于二进制搜索ToRemove
的复杂性,您可能需要对O(log n)
进行排序(您需要重写_ => ToRemove.Any(_.Contains)
)。
但是,相反,对HashSet<string>
使用List<string>
而不是ToRemove
会更快,因为在哈希集中查找元素(使用Contains
)是{{ 1}}操作。
另外,将O(1)
用于LinkedList<string>
可能会有所益处,因为由于数组大小的调整,从链接列表中删除项目通常比从基于数组的列表中删除要快。
答案 1 :(得分:1)
由于这是删除包含另一个列表中的字符串的字符串,所以HashSet不会有太大帮助。实际上,除非您要查找完全匹配的内容或维护所有子字符串的索引(否则,这很昂贵),而昂贵的AFIK仅SQL Server在BigData领域之外半有效地做到这一点。 如果您关心的只是它以“ ToRemove”中的项目开头,则排序可能会有所帮助。在“ ToRemove”自定义二进制搜索中对“ MyList”和foreach字符串进行排序,以找到以该字符串和RemoveAt索引开头的任何字符串,直到没有开头为止,然后再递减索引,直到没有开头为止。