Python 此函数同时检索最小值和最大值是否比单独使用最小值和最大值快?
我有一个函数可以同时检索列表的最小值和最大值:Python 此函数同时检索最小值和最大值是否比单独使用最小值和最大值快?,python,max,min,Python,Max,Min,我有一个函数可以同时检索列表的最小值和最大值: def min_max(iterable, key=None): """Retrieve the min and max values of `iterable` simultaneously.""" if key is None: key = lambda x: x if not iterable: return None, None min_ = max_ = key(iterable[0])
def min_max(iterable, key=None):
"""Retrieve the min and max values of `iterable` simultaneously."""
if key is None: key = lambda x: x
if not iterable:
return None, None
min_ = max_ = key(iterable[0])
for i in iterable[1:]:
if key(i) > key(max_): max_ = i
if key(i) < key(min_): min_ = i
return min_, max_
def min_max(iterable,key=None):
“”“同时检索'iterable'的最小值和最大值。”“”
如果key为None:key=lambda x:x
如果不适用:
返回None,None
最小值=最大值=键(iterable[0])
因为我在iterable[1:]:
如果键(i)>键(max):max=i
如果键(i)<键(最小值):最小值=i
返回最小值,最大值_
但这让我想知道,既然我在for循环中进行了两次比较,单独使用
min
和max
会不会更快?如果是,我如何编辑此函数以提高效率?在列表中查找最小值或最大值的代价不是比较。比较值非常快,在这里不会产生问题。相反,影响运行时的是循环
当您使用min()
或max()
时,它们中的每一个都必须在iterable上迭代一次。它们是分开做的,所以当您需要最小值和最大值时,通过使用内置函数,您需要迭代两次
您的函数只需在其上迭代一次,因此其理论运行时间较短。现在,正如chepter在评论中提到的,min
和max
都是实现的,因此它们肯定比您自己在Python代码中实现时要快
现在,这在很大程度上取决于您的iterable,这两个本机循环是否比Python函数快。对于较长的列表,迭代它已经很昂贵,迭代一次肯定会更好,但对于较短的列表,您可能会使用本机代码获得更好的结果。我不知道确切的阈值在哪里,但是你可以很容易地测试出你的实际数据什么更快。不过,在大多数情况下,它很少起作用,因为最小/最大值不会成为应用程序的瓶颈,所以在它成为问题之前,您不应该担心它
顺便说一句,您的实现现在有一些问题,如果您想使用它,您应该解决这些问题:
- 它要求
是一个序列,而不是一个iterable(因为您对它使用索引)iterable
- 您还要求它至少有一个技术上不需要的项目。虽然您确实检查了
,但这并不一定会告诉您有关序列/可编辑长度的信息。自定义类型可以轻松提供自己的布尔值和/或序列行为不可编辑
- 最后,使用iterable项的键控值初始化
和\u min
,但稍后(正确地)只从iterable中分配原始项\u max
it = iter(iterable)
try:
min_ = max_ = next(it)
minv = maxv = key(min_)
except StopIteration:
return None, None
for i in it:
k = key(i)
if k > maxv:
max_, maxv = i, k
elif k < minv:
min_, minv = i, k
使用此代码:
for i in iterable[1:]:
if key(i) > key(max_):
max_ = i
elif key(i) < key(min_):
min_ = i
iterable[1:]中的i的
如果键(i)>键(最大值):
最大值=i
elif键(i)<键(最小值):
最小值=i
请检查此处:
这并不完全是您所看到的,但我可以减少循环:
def min_max(iterable):
if not iterable:
raise Exception('Required iterable object')
_min = _max = iterable[0]
ind = 0
if len(iterable) & 1:
ind = 1
for elm in iterable[1::2]:
ind += 2
try:
if iterable[ind] < iterable[ind + 1]:
if _min > iterable[ind]:
_min = iterable[ind]
if _max < iterable[ind + 1]:
_max = iterable[ind + 1]
else:
if _min > iterable[ind + 1]:
_min = iterable[ind + 1]
if _max < iterable[ind]:
_max = iterable[ind]
except:
pass
return _min, _max
print min_max([11,2,3,5,0,1000,14,5,100,1,999])
假设
iterable
中至少有一个键。否则,这将在调用min\ux=max\ux…
时消失。为什么要使用一个只返回其参数的函数来访问这些值?折衷是在Python级别对列表进行一次遍历,而在C级别进行两次遍历。哪种方法更快可能取决于列表的长度,但我怀疑,除了非常大的列表之外,后者将更快。对其进行分析并查看。难道您不能对min-anelif
进行第二次检查吗?一次通过算法在处理任意iterable时可能具有相当大的优势,但使用iterable[0]
和iterable[1://code>则否定了这一点;没有回答这个问题。也不知道你在那里做什么…好吧,我提供了一个更好的解决方案,如果业主不喜欢,我会删除它。我正在将循环数减少到n/2,@user3398620如果您不喜欢,请告诉我:)我将删除它。好吧,我可以随时进行循环展开以删除迭代;但这不会改变复杂性(我认为这会使函数更加复杂)。此外,您的解决方案不支持键函数,并且还基于不可编辑的序列(甚至比OP更为如此)。我不是向下投票人,但我想指出,对于较长的列表,仅迭代一次应该比迭代两次更快的想法是误导的。考虑的两种算法都是O(N)
,因此无论输入的大小,它们的相对速度应该保持不变。只有当输入相当大时(为了克服任何可能不同的恒定开销),这才可能是正确的,但是从10000项到1000000项的相对性能不会有太大的差异。@Blckknght当然,它们在O表示法中被认为是相等的,但它们仍然有不同的执行时间,这在优化代码时往往很重要。如果您在应用程序中反复计算最小值和最大值,那么您可能希望对此进行一些微优化,并选择一个更快的值,即使两者都是O(n)
。如果你读了我的答案,你会发现,虽然我指出了不同之处,但实际上我还是建议使用单独的函数,因为微优化通常是不必要的。
def min_max(iterable):
if not iterable:
raise Exception('Required iterable object')
_min = _max = iterable[0]
ind = 0
if len(iterable) & 1:
ind = 1
for elm in iterable[1::2]:
ind += 2
try:
if iterable[ind] < iterable[ind + 1]:
if _min > iterable[ind]:
_min = iterable[ind]
if _max < iterable[ind + 1]:
_max = iterable[ind + 1]
else:
if _min > iterable[ind + 1]:
_min = iterable[ind + 1]
if _max < iterable[ind]:
_max = iterable[ind]
except:
pass
return _min, _max
print min_max([11,2,3,5,0,1000,14,5,100,1,999])
(0, 1000)