2013-06-05 32 views
0

最大元素如果有這樣的列表:我怎樣才能獲得的最小和列表的蟒蛇

l = [1,2,3,4,5] 

,我想在結尾處

min = 1 
max = 5 

min(l)max(l)

+1

有沒有使用最小和最大的有效理由? – abhishekgarg

+1

你能告訴你爲什麼不想用'min(l)'/'max(l)'?因爲如果我在這裏回答你的問題,我會給你一個非常接近min()和max()已經完成的算法。 – zmo

回答

-1

我能想到的是排序的原始列表,然後選擇第一個和最後一個元素最快的方法。這避免了多次循環,但它確實會破壞列表的原始結構。這可以通過簡單地複製列表並僅對複製列表進行排序來解決。我很好奇,如果這是不是僅僅使用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 

排序算法對大型陣列很慢。

+0

您需要使用'timeit'模塊來消除方差(CPU調度,交換等);它也會爲您的平臺選擇正確的計時器(最準確的選項)。 –

+1

而一個簡單的循環是O(n)的複雜度,排序是O(n log n);這可能是因爲python for循環的不變成本高於排序的C代碼常量成本,這就是爲什麼排序後短列表可能會更快,但對於大列表循環會贏,給定足夠大的名單。 –

+1

最後一個數據點:使用一個正確的隨機列表來測試sort()對一個循環或者min()和max()調用;排序算法(TimSort)針對部分排序的數據進行了優化;你的輸入樣本大多是排序的(只有'3'不在位)。 –

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

你應該更好地給他提示,而不是給他答案,stackoverflow不是爲學生做作業! :-s(儘管你使用float的'inf'的想法很整潔;-)) – zmo

+3

不,Stack Overflow用於回答問題。 OP從來沒有要求提示,我們不是在這裏警察的作業政策。如果我是教授,如果將其作爲家庭作業答案發布,以瞭解學生是否瞭解其確切* *,我*會在答案中詢問有關代碼的尖銳問題。 –

+2

在這種情況下,我會使用'iterable = iter(l); minimum = maximum = next(iterable)'「pattern」。它具有額外的優點,即它可以處理每個序列,而'l [0]'僅適用於索引序列。 – Bakuriu

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 
+4

爲什麼雙循環?你可以在這裏避免循環兩次。 –

+0

的確如此,但我認爲從教育的角度來看更清楚。 – DXsmiley

+3

@DXsmiley我不同意 – jamylak

1

好吧,因爲這是一項任務,我不會給你任何代碼,你必須自己弄明白。但基本上,您可以在列表中循環,例如創建兩個變量iMiniMax,並將每個值與iMiniMax對比,然後將新變量iBuf分配給該值。

+0

這些名稱似乎太過java-ish或任何語言使用camelCase + prepending類型,我認爲這是完全醜陋和誤導在這個示例中(其中函數將支持任何類型的支持比較)。 – Bakuriu

+0

我說的是一般算法,不是具體的python,我用'i'來表示'index',而不是'整數'。我不喜歡python中的camelCase,順便說一句。 – zmo

1

怪異限制家庭作業問題,要求回答作弊

>>> l = [1,2,3,4,5] 
>>> sorted(l)[::len(l)-1] 
[1, 5] 
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 
0

如果你只需要一個通過列表循環,您可以使用一個reduce(不那麼)創造性的方式。助手功能可能已經降低拉姆達,但我不這樣做是爲了便於閱讀的緣故

>>> 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) 
1

爲了找到最大:

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()))