例如,如果我有一个功能可以检查list1是否为list2的子列表,哪个选项更好:
选项1:
def isSublist1(list1,list2):
"This fuction checks if list1 is a sublist of list2."
for i in range(len(list2)):
part=list2[i:] # part is a list with all the elements from i to the end of list2
if len(part)<len(list1):
return False
if list1==part[:len(list1)]: # if list1 is in the beginning of part
return True
return False
或选项2:
def isSublist2(list1,list2):
"This fuction checks if list1 is a sublist of list."
for i in range(len(list2)):
if len(list2[i:])<len(list1):
return False
if list1==list2[i:][:len(list1)]: # if list1 is in the beginning of list2[i:] (part)
return True
return False
在选项1中,我使用名为part
的变量来存储list2
的一部分,但是在选项2中,part
不是变量,是{{1}的部分}在需要时进行计算。选项1更快吗?它会花费更多空间吗?
我的问题不是专门针对此功能的,我知道还有其他方法可以实现此功能。
我想知道哪一个是循环中的最佳实践:使用变量来避免多次计算相同的事物。答案是否取决于计算的复杂性和频率?
答案 0 :(得分:2)
存储本地更好,因为python的查找速度更快。甚至还可以在本地存储功能。
最好通过定时对性能问题进行解答-您可以使用timeit对其进行度量:
import timeit
def noTempFunc():
for _ in range(200):
max([1,4,5,6])
def tempFunc():
m = max
for _ in range(200):
m([1,4,5,6])
print(timeit.timeit(noTempFunc, number=1000)) # 0.055301458000030834
print(timeit.timeit(tempFunc, number=1000)) # 0.049811941999905684 : 11% faster
在这种情况下,全局上下文的max()
只需要查找一次,并且在本地进行进一步的查找,基于这些数字,查找速度要快11%。
如果您多次使用本地m()
,则可以付费。
在您的情况下,缓存len_list1 = len(list1)
是明智的-因为它使用了很多时间并且不会更改。
要使其更具可读性,可以考虑:
def isSublist(list1, list2):
"""Checks if list2 is a sublist of list1"""
len_part = len(list2) # reused inside the list comp, only "calulated" once
return any( x == list2 for x in (list1[i:i+len_part]
for i in range(len(list1)-len_part+1) ))
print(isSublist([1,2,3,4],[1]))
print(isSublist([1,2,3,4],[2,3]))
print(isSublist([1,2,3,4],[1,2,4]))
print(isSublist([1,2,3,4],[1,2,3,4]))
输出:
True
True
False
True
查询:
您的更快版本以及已缓存的长度(基于Scott Mermelstein答案):
def isSublist1a(list1,list2): # cached length as well
l1 = len(list1)
for i in range(len(list2)):
part=list2[i:]
if len(part)<l1:
return False
if list1==part[:l1]:
return True
return False
list1=list(range(1000))
list2=list(range(400,420))
import timeit
print(timeit.timeit('isSublist1(list2,list1)', globals=globals(),number=1000))
print(timeit.timeit('isSublist1a(list2,list1)', globals=globals(),number=1000))
print(timeit.timeit('isSublist2(list2,list1)', globals=globals(),number=1000))
传送(两次执行):
0.08652938600062043 # cached part
0.08017484299944044 # cached part + cached list1 lenght - slightly faster
0.15090413599955355 # non-cached version
0.8882850420004615 # cached part
0.8294611960000111 # cached part + cached list1 lenght - slightly faster
1.5524438030006422 # non-cached version
答案 1 :(得分:2)
作为Patrick出色的answer的补充,让我们尝试使用您的实际代码进行计时:
>>> def isSublist1(list1,list2):
... for i in range(len(list2)):
... part=list2[i:]
... if len(part)<len(list1):
... return False
... if list1==part[:len(list1)]:
... return True
... return False
...
>>> def isSublist2(list1,list2):
... for i in range(len(list2)):
... if len(list2[i:])<len(list1):
... return False
... if list1==list2[i:][:len(list1)]:
... return True
... return False
...
>>> list1=list(range(10000))
>>> list2=list(range(4000,4020))
>>> import timeit
>>> timeit.timeit('isSublist1(list2,list1)', globals=globals(),number=100)
6.420147094002459
>>> timeit.timeit('isSublist2(list2,list1)', globals=globals(),number=100)
12.455138996010646
因此,在我的系统上,使用临时变量所需的时间仅为不使用临时变量所需时间的一半。
我不知道您的列表和子列表的性质;您可能需要更改list1和list2以便更好地反映代码的使用方式,但是至少在我这方面,保存临时变量似乎是个好主意。
顺便说一句,让我们做另一个有趣的实验:
>>> def isSublist3(list1,list2):
... ln = len(list1)
... for i in range(len(list2)):
... part=list2[i:]
... if len(part)<ln:
... return False
... if list1==part[:ln]:
... return True
... return False
...
>>> timeit.timeit('isSublist1(list2,list1)',globals=globals(),number=100); timeit.timeit('isSublist3(list2,list1)',globals=globals(),number=100)
6.549526696035173
6.481004184985068
我又跑了几次,看看能得到什么:
6.470875242026523 6.463623657007702
6.151073662971612 5.787795798969455
5.685607994964812 5.655005165026523
6.439315696014091 6.372227535001002
请注意,每次缓存的时间比未缓存的时间要少,尽管通过缓存切片并不能获得与性能几乎相同的改善。
还请注意,不要一次运行就得出太多结论,这一点很重要。还有很多其他因素会影响时间,(在我的例子中,很明显,在一次测试中,发生了一些事情使它从6.4下降到5.7!),所以如果您想提出一个好的规则您可以依靠,进行几次测试以确保获得一致的结果。