您不需要将两个list
s 都转换为set
s,只需一个。我认为跳过不必要的转换使其更具可读性和优雅性。
所以,要么:
set(a).intersection(b)
或者:
s = set(a)
any(e in s for e in b)
后者的优点是一旦找到一个匹配项就会短路,更好地表达逻辑,并返回True
orFalse
而不是 non-falsey 或 falsey set
,但如果这让您感到困扰,它是两行而不是一行。我不知道这个优势是否抵消了将循环放在生成器表达式而不是 C 函数中的成本。
s 这么小的性能结果list
几乎没有意义,所以让我们试试这个:
In [373]: a=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [374]: b=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [375]: %timeit(set(a))
10000 loops, best of 3: 180 us per loop
In [376]: s=set(a) # since all versions need to do this
In [391]: %timeit(s & set(b))
1000000 loops, best of 3: 178 us per loop
In [392]: %timeit(s.intersection(b))
1000000 loops, best of 3: 247 us per loop
In [393]: %timeit(discard(e in s for e in b))
1000000 loops, best of 3: 550 ns per loop
In [394]: %timeit(any(e in s for e in b))
1000000 loops, best of 3: 749 ns per loop
In [395]: %timeit(any(e in a for e in b))
1000000 loops, best of 3: 1.42 us per loop
要将数字全部放在纳秒级,再加上set(a)
除了最后需要的所有成本,并比较三个 Python 版本的相同测试(Apple 股票 CPython 2.7.2、python.org CPython 3.3.0、Homebrew PyPy 1.9.0/2.7.2,所有 64 位 Mac 版本):
CP272 CP330 PyPy
s & set(b) 358000 316000 180500
s.intersection(b) 427000 459000 180900
discard(genexp) 180550 157341 90094
any(genexp) 180749 157334 90208
any(list-genexp) 1420 686 960
现在回想起来,这完全有道理。很早就发生碰撞的几率非常高,因此将整个东西转换为一组的成本决定了一切。
这意味着我们需要一个具有 10000 个唯一值的新测试。让我们重复测试,这样:
In [29]: a, b = list(range(10000)), list(range(10000))
In [30]: random.shuffle(a)
In [31]: random.shuffle(b)
CP272 CP330 PyPy
s & set(b) 1277000 1168000 1141000
s.intersection(b) 1165000 1117000 2520000
discard(genexp) 1699000 1271000 770000
any(genexp) 389800 344543 320807
any(list-genexp) 62000 10400 1520
这些更合理。他们仍然有意义。如果您要比较相同的 10000 个随机打乱的元素,那么每个元素要走多远?还不足以使set
-ify 任何一个列表的成本都值得做,更不用说它们两个了!
所以,让我们尝试一个没有匹配的情况:
In [43]: a=list(range(10000, 20000))
CP272 CP330 PyPy
s & set(b) 751000 770000 733000
s.intersection(b) 466000 530000 1920000
discard(genexp) 1246000 985000 749000
any(genexp) 1269000 966000 893000
any(list-genexp) 185000000 176000000 5870000
我不知道 PyPy 是如何如此快速地完成最后一个,但除此之外,这里没有任何惊喜。
那么,哪一个最好呢?
显然,如果您预计会有很多冲突,那么您希望尽可能避免制作集合——但如果您预计很少有冲突,您希望至少制作一组。如果你不知道,我认为最安全的赌注是any(genexp)
——最坏的情况是最好的情况的不到 3 倍,如果有可能碰撞率很高,它会快很多。但是您可以查看数字并亲自查看。
或者,当然更好的是,根据您期望遇到的真实测试数据对它们进行计时。