Python 为什么字符串搜索比列表搜索和集合搜索最快?

Python 为什么字符串搜索比列表搜索和集合搜索最快?,python,string,python-2.7,Python,String,Python 2.7,我正在解决一些有竞争力的编码挑战。当我在列表中搜索时,我的解决方案超出了时间限制,但当我在字符串中搜索时被接受 下面是一个示例代码: 代码 import timeit list = timeit.Timer("'A' in list('AEIOU')") set = timeit.Timer("'A' in set('AEIOU')") string = timeit.Timer("'A' in 'AEIOU'") print 'List search :',list.timeit(9999

我正在解决一些有竞争力的编码挑战。当我在列表中搜索时,我的解决方案超出了时间限制,但当我在字符串中搜索时被接受

下面是一个示例代码:

代码

import timeit

list = timeit.Timer("'A' in list('AEIOU')")
set = timeit.Timer("'A' in set('AEIOU')")
string = timeit.Timer("'A' in 'AEIOU'")

print 'List search :',list.timeit(999999)
print 'Set search',set.timeit(999999)
print 'String search',string.timeit(999999)
输出

List search : 1.0873670578
Set search 1.0083398819
String search 0.0997061729431
*此输出是在ideone.com上获得的
**输出可能因系统而异,但趋势相同


我发现字符串搜索速度快得难以置信。我在谷歌上搜索了一下,但没有找到令人满意的理由。请帮助我理解为什么字符串搜索最快

您的测试是有偏差的,您需要使用
设置
参数来忽略创建
列表
设置

>>> timeit.timeit("'A' in l", "l = list('AEIOU')")
0.06389708405846951
>>> timeit.timeit("'A' in s", "s = set('AEIOU')")
0.05960524183085081
>>> timeit.timeit("'A' in s", "s = 'AEIOU'")
0.05756433387793081

也就是说,对于
str
list
操作中的
是线性的
O(N)
set
是常量
O(1)
(忽略大量哈希冲突)。因此,对于一个更大的例子来说,
set
将是最快的,而
str
list
将非常相似。

这与实际搜索速度几乎没有关系,与必须查找全局名称(
set
list
)并调用该全局名称有关(包括帧保存和恢复)

仅在
操作员中测试实际的
,而不是在呼叫时:

>>> import timeit
>>> timeit.Timer("'A' in l", "l = list('AEIOU')").timeit(999999)
0.0490870475769043
>>> timeit.Timer("'A' in s", "s = set('AEIOU')").timeit(999999)
0.0507349967956543
>>> timeit.Timer("'A' in s", "s = 'AEIOU'").timeit(999999)
0.04982495307922363
现在时间太近,无法调用,因为您的对象太小。请使用更大的输入来实际查看差异

仅仅使用更多的字符已经在一定程度上增加了对比度:

>>> timeit.Timer("'A' in l", "from string import ascii_letters, digits, whitespace; l = list(ascii_letters + digits + whitespace)").timeit(999999)
0.38520193099975586
>>> timeit.Timer("'A' in s", "from string import ascii_letters, digits, whitespace; s = set(ascii_letters + digits + whitespace)").timeit(999999)
0.046868085861206055
>>> timeit.Timer("'A' in s", "from string import ascii_letters, digits, whitespace; s = ascii_letters + digits + whitespace").timeit(999999)
0.06492304801940918
现在
set()

如果对象中不存在字符,则还应测试否定情况:

>>> timeit.Timer("'\xff' in l", "from string import ascii_letters, digits, whitespace; l = list(ascii_letters + digits + whitespace)").timeit(999999)
0.909243106842041
>>> timeit.Timer("'\xff' in s", "from string import ascii_letters, digits, whitespace; s = set(ascii_letters + digits + whitespace)").timeit(999999)
0.05034899711608887
>>> timeit.Timer("'\xff' in s", "from string import ascii_letters, digits, whitespace; s = ascii_letters + digits + whitespace").timeit(999999)
0.09932804107666016
这里的
set()
对象真的很出色


请注意,在这两种情况下,字符串搜索仍然优于列表搜索;这是因为在C数组上迭代并比较字节比在动态数组中比较对象要快,在动态数组中,您无法预先知道所有对象都是同一类型。

实际上,检查
set
的成员关系比list和string becau更快使用哈希表和它O(1),但这里看到的不同是因为将字符串转换为set和list。因此,尝试使用
{'A','I','E','U','O'}
['A','I','E','U','O']
,因为您的示例集非常小,
O(1)
for
set
O(N)有优势
对于其他人来说并不重要。而且设置(创建
集合
列表
)无论如何都是
O(N)
。搜索字符串比
列表
更快,因为它的结构更简单(它包含字符数组,而不是对字符串对象的引用)。