为什么将列表转换为集合比仅使用列表计算列表差异更快?

时间:2014-08-13 19:48:22

标签: python performance list python-2.7 set

说,我希望计算两个列表C = A - B的差异:

A = [1,2,3,4,5,6,7,8,9] 
B = [1,3,5,8,9]
C = [2,4,6,7]          #Result

AB都使用唯一的整数进行排序(不确定是否有办法告诉Python有关列表的此属性)。我需要保留元素的顺序。 AFAIK有两种可行的方法

方法1 将B转换为集合并使用列表解析来生成C:

s = set(B)
C = [x for x in A if x not in s]

方法2 直接使用列表理解:

C = [x for x in A if x not in B]

为什么#1#2效率更高?是否有转换为集合的开销?我在这里缺少什么?

this answer.

中给出了一些性能基准

更新:我知道设置的平均O(1)查询时间比列表的O(n)快,但如果原始列表A包含有关百万左右的整数,集合创作实际上不会花费更长时间吗?

3 个答案:

答案 0 :(得分:12)

将列表转换为集合会产生开销,但是一个集合基本比那些in测试的列表更快。

您可以立即查看项目x是否在y集中,因为下面使用的是哈希表。无论你的集合有多大,查找时间都是相同的(基本上是瞬时的) - 这在Big-O表示法中称为O(1)。对于列表,您必须单独检查每个元素,以查看项x是否在列表z中。随着列表的增长,检查将花费更长的时间 - 这是O(n),这意味着操作的长度与列表的长度直接相关。

增加的速度可以抵消设置的创建开销,这就是设置检查最终更快的方式。

编辑:要回答其他问题,Python无法确定您的列表是否已排序 - 无论如何您都使用标准list对象。因此,它不能通过列表理解来实现O(log n)性能。如果你想编写自己的二进制搜索方法,假设列表已经排序,你当然可以这样做,但O(1)任何一天都会击败O(log n)。

答案 1 :(得分:7)

集合中查找(x中的S)的平均时间复杂度为O(1),而列表的相同时间为O(n)。

您可以在https://wiki.python.org/moin/TimeComplexity

查看详细信息

答案 2 :(得分:6)

根据Python documentation on time complexity

  • 列表成员资格x in s是平均线性时间操作,或O(n)
  • 设置成员资格x in s平均为常量时间操作,或O(1)

构建集合是最坏情况的线性时间操作,因为需要扫描列表中的所有元素以构建散列表,因此O(n)n是集合中元素的数量。

关键的观察是,在方法1 中,构建一个集合,s = set(B)只是一次性操作,之后我们只有n总数如x not in B中所述的集合成员资格测试,总计O(n) + n * O(1)O(n)时间复杂度。

方法2 中,对x not in B中的每个元素执行列表成员资格测试A,因此总时间复杂度为n * O(n) = O(n^2)。< / p>