如果有一个列表如:
l = [1,2,3,4,5]
我最后想要
min = 1
max = 5
没有min(l)
和max(l)
。
答案 0 :(得分:7)
如果您试图避免使用两个循环,希望单个循环更快,您需要重新考虑。调用两个O(N)函数仍然为您提供O(N)算法,您所做的只是将每次迭代成本加倍。具有比较的单个Python循环也不能比O(N)做得更好(除非您的数据已经被排序),并且解释每次迭代的字节码也具有相当大的常量成本。哪种方法具有较高的恒定成本只能通过计算运行时间来确定。
要在单个循环中执行此操作,请迭代列表并针对到目前为止找到的最小值和最大值测试每个项目。 float('inf')
和float('-inf')
(无穷大和负无穷大)是简化逻辑的良好起点:
minimum = float('inf')
maximum = float('-inf')
for item in l:
if item < minimum:
minimum = item
if item > maximum:
maximum = item
或者,从第一个元素开始,仅循环其余元素。首先将列表转换为可迭代,将第一个元素存储为结果,然后循环其余元素:
iterl = iter(l)
minimum = maximum = next(iterl)
for item in iterl:
if item < minimum:
minimum = item
if item > maximum:
maximum = item
不要使用排序。 Python的Tim Sort实现是一种O(N log N)算法,可以预期比直接O(N)方法慢。
与更大的随机列表进行时间比较:
>>> from random import shuffle
>>> l = list(range(1000))
>>> shuffle(l)
>>> from timeit import timeit
>>> def straight_min_max(l):
... return min(l), max(l)
...
>>> def sorted_min_max(l):
... s = sorted(l)
... return s[0], s[-1]
...
>>> def looping(l):
... l = iter(l)
... min = max = next(l)
... for i in l:
... if i < min: min = i
... if i > max: max = i
... return min, max
...
>>> timeit('f(l)', 'from __main__ import straight_min_max as f, l', number=10000)
0.5266690254211426
>>> timeit('f(l)', 'from __main__ import sorted_min_max as f, l', number=10000)
2.162343978881836
>>> timeit('f(l)', 'from __main__ import looping as f, l', number=10000)
1.1799919605255127
因此,即使对于1000个元素的列表,min()
和max()
函数也是最快的。排序速度最慢。如果允许就地排序,排序版本可以更快,但是你也需要为每个定时运行生成一个新的随机列表。
移动到一百万个项目(每次定时运行只有10个测试),我们看到:
>>> l = list(range(1000000))
>>> shuffle(l)
>>> timeit('f(l)', 'from __main__ import straight_min_max as f, l', number=10)
1.6176080703735352
>>> timeit('f(l)', 'from __main__ import sorted_min_max as f, l', number=10)
6.310506105422974
>>> timeit('f(l)', 'from __main__ import looping as f, l', number=10)
1.7502741813659668
最后但并非最不重要的是,使用了一百万个项目l.sort()
代替sorted()
:
>>> def sort_min_max(l):
... l.sort()
... return l[0], l[-1]
...
>>> timeit('f(l[:])', 'from __main__ import straight_min_max as f, l', number=10)
1.8858389854431152
>>> timeit('f(l[:])', 'from __main__ import sort_min_max as f, l', number=10)
8.408858060836792
>>> timeit('f(l[:])', 'from __main__ import looping as f, l', number=10)
2.003532886505127
注意l[:]
;我们给每个测试运行一份列表副本。
结论:即使对于大型列表,最好还是使用min()
和max()
函数,因此很难超过良好C循环的低每次迭代成本。但如果你不得不放弃这些功能,那么直接循环是下一个更好的选择。
答案 1 :(得分:1)
使用for循环遍历列表中的所有元素。将存储最大/最小值的变量设置为列表中的第一个元素以开始。否则,您可能会得到无效的值。
max_v=l[0]
for i in l:
if i>max_v:
max_v=i
min_v=l[0]
for i in l:
if l<min_v:
min_v=i
答案 2 :(得分:1)
iMin
和iMax
,并为每个值比较iMin
和iMax
到该值并分配一个新变量iBuf
到那个。
答案 3 :(得分:1)
带有奇怪限制的家庭作业问题需要作弊答案
>>> l = [1,2,3,4,5]
>>> sorted(l)[::len(l)-1]
[1, 5]
答案 4 :(得分:1)
查找max:
print reduce(lambda x,y: x if x>y else y, map(int,raw_input().split()))
寻找分钟:
print reduce(lambda x,y: x if x<y else y, map(int,raw_input().split()))
答案 5 :(得分:0)
我能想到的最快的方法是对原始列表进行排序,然后选择第一个和最后一个元素。这可以避免多次循环,但它会破坏列表的原始结构。这可以通过简单地复制列表并仅对复制的列表进行排序来解决。我很好奇,如果这比使用这个快速示例脚本的max()和min()慢得多:
import time
l = [1,2,4,5,3]
print "Run 1"
t1 = time.time()
print "Min =", min(l)
print "Max =", max(l)
print "time =", time.time() - t1
print ""
print "l =", l
print ""
l = [1,2,4,5,3]
l1 = list(l)
print "Run 2"
t1 = time.time()
l1.sort()
print "Min =", l1[0]
print "Max =", l1[-1]
print "time =", time.time() - t1
print ""
print "l =", l
print "l1 =", l1
print ""
l = [1,2,4,5,3]
print "Run 3"
minimum = float('inf')
maximum = float('-inf')
for item in l:
if item < minimum:
minimum = item
if item > maximum:
maximum = item
print "Min =", minimum
print "Max =", maximum
print "time =", time.time() - t1
print ""
print "l =", l
令人惊讶的是,第二种方法在我的计算机上快了大约10ms。不确定这对于非常大的列表有多高效,但至少对于您提供的示例列表,这种方法更快。
我将@Martijn Pieters的简单循环算法添加到我的计时脚本中。 (因为时间将是这个问题值得探讨的唯一重要参数。)我的结果是:
Run 1: 0.0199999809265s
Run 2: 0.00999999046326s
Run 3: 0.0299999713898s
编辑:包含timeit模块以进行计时。
import timeit
from random import shuffle
l = range(10000)
shuffle(l)
def Run_1():
#print "Min =", min(l)
#print "Max =", max(l)
return min(l), max(l)
def Run_2():
l1 = list(l)
l1.sort()
#print "Min =", l1[0]
#print "Max =", l1[-1]
return l1[0], l1[-1]
def Run_3():
minimum = float('inf')
maximum = float('-inf')
for item in l:
if item < minimum:
minimum = item
if item > maximum:
maximum = item
#print "Min =", minimum
#print "Max =", maximum
return minimum, maximum
if __name__ == '__main__':
num_runs = 10000
print "Run 1"
run1 = timeit.Timer(Run_1)
time_run1 = run1.repeat(3, num_runs)
print ""
print "Run 2"
run2 = timeit.Timer(Run_2)
time_run2 = run2.repeat(3,num_runs)
print ""
print "Run 3"
run3 = timeit.Timer(Run_3)
time_run3 = run3.repeat(3,num_runs)
print ""
print "Run 1"
for each_time in time_run1:
print "time =", each_time
print ""
print "Run 2"
for each_time in time_run2:
print "time =", each_time
print ""
print "Run 3"
for each_time in time_run3:
print "time =", each_time
print ""
我的结果是:
Run 1
time = 3.42100585452
time = 3.39309908229
time = 3.47903182233
Run 2
time = 26.5261287922
time = 26.2023346397
time = 26.7324208568
Run 3
time = 3.29800945144
time = 3.25067545773
time = 3.29783778232
对于大型数组,排序算法非常慢。
答案 6 :(得分:0)
>>> L = [1,2,3,4,5]
>>> reduce(lambda x, y: x if x<y else y, L)
1
>>> reduce(lambda x, y: x if x>y else y, L)
5
另一种方式
>>> it = iter(L)
>>> mn = mx = next(it)
>>> for i in it:
... if i<mn:mn=i
... if i>mx:mx=i
...
>>> mn
1
>>> mx
5
答案 7 :(得分:0)
如果您只需要一个循环浏览列表,则可以使用reduce
a(不是那样)创意方式。辅助函数本来可以减少为lambda,但为了便于阅读,我不这样做:
>>> def f(solutions, item):
... return (item if item < solutions[0] else solutions[0],
... item if item > solutions[1] else solutions[1])
...
>>> L = [i for i in range(5)]
>>> functools.reduce(f, L, (L[0],L[0]))
(0, 4)