Python:使用列表理解来过滤列表的更快方法

时间:2019-02-15 09:29:31

标签: python-3.x list-comprehension binary-search

请考虑以下问题:我想保留属于list2的list1的元素。所以我可以做这样的事情:

name.
  zip(price, weight).
  map(&%i[name price weight].method(:zip)).
  map(&:to_h).
  map(&Fruit.method(:create))

我需要对list1的不同示例(大约20000个不同的示例)和“常量”(冻结)list2重复相同的过程。

我如何加快这一过程?

我还知道以下属性:

1)list1具有重复的元素,并且没有排序,并且大约有10000(一万)个项目。

2)list2是一个巨大的排序列表(在Python中约为200000-20万个条目),每个元素都是唯一的。

首先想到的是,也许我可以使用一种二进制搜索。但是,有没有办法在Python中做到这一点?

此外,我不介意filtered_list是否具有与list1相同的项顺序。因此,也许我只能检查list1的未重复版本,并在删除list1中不属于列表2的元素之后,可以返回重复的项目。

在Python 3中有快速的方法吗?

1 个答案:

答案 0 :(得分:2)

list2转换为set

# do once
set2 = set(list2)

# then every time
filtered_list = [w for w in list1 if w in set2]

x in list2是顺序的; x in set2使用与字典相同的机制,从而可以非常快速地进行查找。

如果list1没有重复项,则将两者都转换为集合并采用集合交集是一种方法:

filtered_set = set1 & set2

但是如果有重复项,您就不得不像上面那样在list1上进行迭代。

(如您所说,您甚至可以使用set1 - set2看到要删除的元素,但是为了删除它们,您仍然会陷入循环中-性能不应有任何差异在过滤守护者与过滤垃圾之间,您仍然必须遍历list1,因此无法克服以上方法。)

编辑以回应评论:如果可以,将list1转换为Counter 可能会(编辑:否;需要测试!)加快处理速度。通常这样使用它(即,您永远没有列表,您总是只处理Counter)。但是,如果每次执行上述操作时都必须将list1预处理为counter1,那再无济于事-创建Counter将再次涉及到循环。