为了找出python中两个列表的替代,我使用:
names_of_files_not_dowloaded = [item for item in total_files if item not in names_of_files_downloaded]
有效。
列表的大小为:
文件总数56373个元素
已下载文件列表28464个元素
持续34秒。 我凭直觉觉得34秒太长了。 有什么方法可以更有效地进行这种扣除吗?
谢谢
编辑: 元素类似于“ AB12345”
列表中没有重复任何元素,它们已经设置好了
答案 0 :(得分:4)
只需将files_downloaded
设置为集合而不是列表。列表可能需要列表的完整迭代才能进行成员资格检查,每次您要进行检查。但是集合是much more efficient to do a lookup on。
只需使用:
downloaded_set = set(files_downloaded)
list_of_files_not_dowloaded = [item for item in total_files if item not in downloaded_set]
将列表放入集合中会产生初始费用,但之后进行成员身份检查会更快。
@ juanpa.arrivillaga在评论中还提到,造成性能下降的另一个原因是in
对字符串进行相等性检查,而使用Sets时比较散列,后者便宜得多。>
如果我正在正确阅读源代码,CPython's lists use a straight equality check to do comparisons when checking for membership似乎是正确的。大概,集使用散列,并且在创建集时将其缓存。
答案 1 :(得分:3)
如果您不关心元素的顺序,并且列表中不包含重复项,则可以简单地使用:
diff = set(total_files) - set(files_downloaded)
如果您需要将输出作为列表:
diff = list(set(total_files) - set(files_downloaded))
set
将覆盖__sub__()
方法,并将其用作您要查找的设置差异。
正如您的问题所述,列表不包含重复项,并且行为类似于集合,这应该可以为您带来相对较好的性能。
答案 2 :(得分:1)
total_files_set = set(total_files)
files_downloaded_set = set(files_downloaded)
files_not_dowloaded_set = total_files_set - files_downloaded_set
list_of_files_not_dowloaded = list(files_not_dowloaded_set)
或者如果您想一行:
list_of_files_not_dowloaded = list(set(total_files) - set(files_downloaded))
要了解有关使用集合的所有操作的更多信息,可以对其进行检查here
编辑:
我尝试使用2个随机列表
timeit.timeit('l = list(set(l1)-set(l2))',
setup='import random; l1 = random.sample(range(1000000), 100000); l2 = random.sample(range(1000000), 50000)',
number = 10)
输出:
0.39393879500130424
timeit.timeit('l = [item for item in l1 if item not in l2]', \
setup='import random; l1 = random.sample(range(1000000), 10000); l2 = random.sample(range(1000000), 5000)', \
number = 1)
输出:
98.58012624000003
如果您碰巧已经拥有了两个集合,而不必从列表中进行转换:
timeit.timeit('l = list(s2-s1)',
setup='import random; s1 = set(random.sample(range(1000000), 100000)); s2 = set(random.sample(range(1000000), 50000))',
number = 10)
输出:
0.06160322100004123