有没有更快的方法来测试两个列表是否具有与==运算符中内置的Pythons完全相同的元素?

时间:2013-08-23 19:53:00

标签: python

如果我有两个列表,每个800个元素长并填充整数。有没有比使用内置==运算符更快的方式来比较它们具有完全相同的元素(如果没有,则为短路)?

a = [6,2,3,88,54,-486]
b = [6,2,3,88,54,-486]
a == b 
>>> True

还有什么比这更好的?

我很好奇只是因为我有一个巨型列表可供比较。

7 个答案:

答案 0 :(得分:10)

我们不要假设,而是进行一些测试!

设置:

>>> import time
>>> def timeit(l1, l2, n):
        start = time.time()
        for i in xrange(n):
                l1 == l2
        end = time.time()
        print "%d took %.2fs" % (n, end - start)

两个巨大的平等名单:

>>> hugeequal1 = [10]*30000
>>> hugeequal2 = [10]*30000
>>> timeit(hugeequal1, hugeequal2, 10000)
10000 took 3.07s

第一个元素不相等的两个巨型列表:

>>> easydiff1 = [10]*30000
>>> easydiff2 = [10]*30000
>>> easydiff2[0] = 0
>>> timeit(easydiff1, easydiff2, 10000)
10000 took 0.00s
>>> timeit(easydiff1, easydiff2, 1000000)
1000000 took 0.14s

因此看起来内置列表相等运算符确实会发生短路。

编辑:有趣的是,使用array.array模块并没有让它更快:

>>> import array
>>> timeit(hugeequal1, hugeequal2, 1000)
1000 took 0.30s
>>> timeit(array.array('l', hugeequal1), array.array('l', hugeequal2), 1000)
1000 took 1.11s

numpy确实可以帮助您提高速度:

>>> import numpy
>>> timeit(hugeequal1, hugeequal2, 10000)
10000 took 3.01s
>>> timeit(numpy.array(hugeequal1), numpy.array(hugeequal2), 10000)
10000 took 1.11s

答案 1 :(得分:4)

Numpy可以将此速度提高10倍,因为您的列表属于修复(整数)类型,因此特别相关。

在纯python中,每个比较都必须遵循对下一个元素的引用,检查类型等。在numpy中,只需要增加一个指针。

以下是比较:

import numpy as np
from timeit import timeit

N = 10**7

p0 = list(range(N))
p1 = list(range(N))

n0 = np.arange(N)
n1 = np.arange(N)

number = 500
t = timeit("p0==p1", setup="from __main__ import p0, p1", number=number)
print "pure python time =", t/number

number = 500
t = timeit("(n0==n1).all()", setup="from __main__ import n0, n1", number=number)
print "numpy time =", t/number

使用numpy的结果快了10倍:

pure python time = 0.256077399254
numpy time = 0.0286148643494

答案 2 :(得分:3)

CPython的内置功能(我假设您正在使用)倾向于用C语言编写。因此,除非您编写一些利用上下文某些方面的C / C ++代码,否则您将无法获得更快的速度。

答案 3 :(得分:3)

另一种选择是使用pypy

$ python -mtimeit -s 'a=[10]*30000;b=[10]*30000;print(a==b)'
100000000 loops, best of 3: 0.0104 usec per loop

$ pypy -mtimeit -s 'a=[10]*30000;b=[10]*30000;print(a==b)'
1000000000 loops, best of 3: 0.00102 usec per loop

而且,pypy的输入速度提高了10倍。

答案 4 :(得分:2)

不,如果两个列表更快,则无法进行比较。但是你说你有一个巨大的清单列表。这听起来像是在问错误的问题。如果我们假设您想要的是找到列表列表中相同的列表,那么是的,有更快的方法:

>>> list_of_lists = [[1,2,3,4,5,6,7], [1,3,3,4,5,6,7], [1,2,3,4,5,6,6], [1,2,3,4,5,6,7]]
>>> list_of_hashes = [hash(tuple(x)) for x in list_of_lists]
>>> list_of_hashes
[1738718158840515323, -9068250430673137562, 1738718158842010488, 1738718158840515323]

正如你在这里看到的,我从每个列表中创建一个哈希(我必须先将它们变成元组,因为列表不可清除)。然后比较是微不足道的,因为你现在只有一个整数列表而不是列表列表。如果您不关心列表中项目的顺序,请使用hash(set(x))

>>> list_of_hashes[0] == list_of_hashes[1]
False
>>> list_of_hashes[0] == list_of_hashes[2]
False
>>> list_of_hashes[0] == list_of_hashes[3]
True

如果您有许多长列表,并且您要将所有列表与所有其他列表进行比较,则速度会快得多。

答案 5 :(得分:1)

没有办法。知道两个项是否相等的唯一方法是比较它们,你必须比较所有对才能知道它们是否相等。

那就是说,无论如何你都可能获得加速。如果您正确使用NumPy ndarrays,NumPy不仅可以加速您的比较,还可以加速您对数据执行的所有操作。或者,如果您可以使用某些外部信息,或者一对列表是否相等以及另一对列表是否相等,则您可以利用该信息来避免某些比较工作。

答案 6 :(得分:0)

根据您的用例,您可以切换到使用元组(不可变),并将列表放在一个集合中。

您的另一个选择是在构建列表时跟踪相似性(或不相似)。