如何最好地编写Python函数(check_list
)以有效地测试元素(x
)是否在列表中n
次出现l
)?
我的第一个想法是:
def check_list(l, x, n):
return l.count(x) >= n
但是,x
找到n
次并且始终为O(n)时,这不会发生短路。
一种简单的短路方法是:
def check_list(l, x, n):
count = 0
for item in l:
if item == x:
count += 1
if count == n:
return True
return False
我还有一个更紧凑的带发电机的短路解决方案:
def check_list(l, x, n):
gen = (1 for item in l if item == x)
return all(next(gen,0) for i in range(n))
还有其他好的解决方案吗?什么是最有效的方法?
谢谢
答案 0 :(得分:22)
您可以使用{{3},而不是通过设置range
对象并使用必须测试每个项目的真实性的all
来产生额外开销}提前生成n
步骤,然后如果切片存在则返回切片中的 next 项,否则返回默认False
:
from itertools import islice
def check_list(lst, x, n):
gen = (True for i in lst if i==x)
return next(islice(gen, n-1, None), False)
请注意,与list.count
类似,itertools.islice
也以C速度运行。这具有处理非列表的迭代的额外优势。
有些时间:
In [1]: from itertools import islice
In [2]: from random import randrange
In [3]: lst = [randrange(1,10) for i in range(100000)]
In [5]: %%timeit # using list.index
....: check_list(lst, 5, 1000)
....:
1000 loops, best of 3: 736 µs per loop
In [7]: %%timeit # islice
....: check_list(lst, 5, 1000)
....:
1000 loops, best of 3: 662 µs per loop
In [9]: %%timeit # using list.index
....: check_list(lst, 5, 10000)
....:
100 loops, best of 3: 7.6 ms per loop
In [11]: %%timeit # islice
....: check_list(lst, 5, 10000)
....:
100 loops, best of 3: 6.7 ms per loop
答案 1 :(得分:13)
您可以使用index
的第二个参数来查找后续的出现指数:
def check_list(l, x, n):
i = 0
try:
for _ in range(n):
i = l.index(x, i)+1
return True
except ValueError:
return False
print( check_list([1,3,2,3,4,0,8,3,7,3,1,1,0], 3, 4) )
index
参数官方文档在其Python Tutuorial, section 5方法的第二或第三个参数中未提及,但您可以在更全面的Python Standard Library, section 4.6中找到它:
在 s 中首次出现 x 的
s.index(x[, i[, j]])
索引(在索引 i 之后或之后Ĵ)(8) (8)
index
在 s 中找不到 x 时会引发ValueError
。支持时,索引方法的附加参数允许有效搜索序列的子部分。传递额外的参数大致相当于使用s[i:j].index(x)
,只是没有复制任何数据,并且返回的索引是相对于序列的开头而不是切片的开头。
在将此list.index
方法与islice(gen)
方法进行比较时,最重要的因素是要找到的事件之间的距离。一旦该距离平均为13或更高,list.index
具有更好的性能。对于较低距离,最快的方法还取决于要查找的出现次数。找到的次数越多,islice(gen)
方法在平均距离方面越早出现list.index
:当出现次数变得非常大时,此增益会逐渐消失。
下图绘制(近似)边界线,两种方法的表现同样良好(X轴为对数):
答案 2 :(得分:2)
如果您预计大量案例将导致提前终止,最终短路是可行的方法。让我们探讨一下可能性:
以list.index
方法与list.count
方法为例(根据我的测试,这两个方法最快,但是ymmv)
对于list.index
,如果列表包含n个或更多个x,则该方法被调用n次。在list.index方法中,执行速度非常快,允许比自定义生成器快得多的迭代。如果x的出现相距足够远,那么index
的低级执行将会看到大的加速。如果x的实例靠得很近(更短的列表/更常见的x),那么将花费更多的时间来执行调解函数其余部分的较慢的python代码(循环n
并递增{{1} })
i
的好处是它可以在慢速python执行之外完成所有繁重工作。这是一个更容易分析的功能,因为它只是O(n)时间复杂度的一个例子。通过在python解释器中几乎没有花费任何时间,但是对于短列表而言,它几乎是最快的。
选择标准摘要:
list.count
list.count
list.count
答案 3 :(得分:0)
我建议您使用Counter
模块中的collections
。
from collections import Counter
%%time
[k for k,v in Counter(np.random.randint(0,10000,10000000)).items() if v>1100]
#Output:
Wall time: 2.83 s
[1848, 1996, 2461, 4481, 4522, 5844, 7362, 7892, 9671, 9705]
答案 4 :(得分:0)
这显示了另一种方法。
查找该索引处的元素是否与您要查找的项目相同。
def check_list(l, x, n):
_l = sorted(l)
try:
index_1 = _l.index(x)
return _l[index_1 + n - 1] == x
except IndexError:
return False
答案 5 :(得分:-1)
c=0
for i in l:
if i==k:
c+=1
if c>=n:
print("true")
else:
print("false")
答案 6 :(得分:-2)
另一种可能性可能是:
def check_list(l, x, n):
return sum([1 for i in l if i == x]) >= n