Bir listede maksimum değeri ve dizinini bulmanın pythonic yolu?


151

Bir listedeki maksimum değeri istersem, sadece yazabilirim max(List), ancak maksimum değerin dizinine de ihtiyacım olursa ne olur?

Böyle bir şey yazabilirim:

maximum=0
for i,value in enumerate(List):
    if value>maximum:
        maximum=value
        index=i

Ama bana sıkıcı geliyor.

Ve eğer yazarsam:

List.index(max(List))

Sonra listeyi iki kez yineleyecektir.

Daha iyi bir yol var mı?


Ne demek "listeyi iki kez geçecek"? List.index (max (Liste)) benim için çalışıyor.
mwcz

14
@mwc: Maksimum değeri belirlemek için listeyi bir kez yineleyecek, daha sonra bu değerin dizinini bulmak için ikinci kez yineleyecektir.

10
Yinelenen maksimum değerler varsa list.index () sorunu olmaz mı?
Logan Yang

@LoganYang evet aynı değere sahip iki öğe olabilir.
Florian

Sipariş önemli değilse, List.sort () [- 1]
Florian

Yanıtlar:


186

Birçok seçenek var, örneğin:

import operator
index, value = max(enumerate(my_list), key=operator.itemgetter(1))

2
Ah, bunu başka yerlerde gördüm, ama sadece bir değer döndüreceğini düşündüm, bir demet değil.
Güneşli88

1
@ Sunny88: keyİşlev yalnızca hangi öğenin maksimum olduğuna karar vermek için kullanılır. Elemanlar değişmez.
Sven Marnach

6
@SvenMarnach Neden key=lambda e: e[1]yerine ve böylece ithalat önlemek?
cankurtaran

8
@lifebalance Kullanımı itemgetter()daha hızlıdır ve bir içe aktarmadan kaçınmak izlemeye değer bir hedef değildir. Dış bağımlılıklardan kaçınmak bazı durumlarda faydalı olabilir, ancak standart kitaplıktan içe aktarma sorun değildir.
Sven Marnach

324

Bence kabul edilen cevap harika ama neden bunu açıkça yapmıyorsun? Daha fazla insanın kodunuzu anlayacağını hissediyorum ve bu PEP 8 ile uyumludur:

max_value = max(my_list)
max_index = my_list.index(max_value)

Bu yöntem de kabul edilen yanıttan yaklaşık üç kat daha hızlıdır:

import random
from datetime import datetime
import operator

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

if __name__ == "__main__":
    from timeit import Timer
    t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Explicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

    t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Implicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

Bilgisayarımda çalıştıkları gibi sonuçlar:

Explicit: 8.07 usec/pass
Implicit: 22.86 usec/pass

Diğer set:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass

3
Daha hızlı olmasını beklemiyordum. L yerine "l = [random.random () in _ in xrange (10000000)] + [2]" yazdığımda bile daha hızlıdır.
Sunny88

14
@ Sunny88: Basit bir sayı listesi için basit yaklaşım daha hızlıdır. Bu durumda performans numpy.argmax()peşindeyseniz, makinemde 30 kat daha hızlı olmasını öneririm . Listede yalnızca sayılardan daha karmaşık nesneler varsa, cevabımdaki yaklaşım daha hızlı olabilir. Bu yaklaşımın bir diğer avantajı, yalnızca listeler için değil, rasgele yineleyiciler için kullanılabilmesidir.
Sven Marnach

@ Sven-Marnach Listemi önce numpy dizisine dönüştürmek zorunda kalsaydım numpy daha hızlı olurdu? Basit örnek için daha hızlı olur mu [0,1,0]?
tommy.carstensen

1
@ Sven-Marnach Az önce kontrol ettim. numpy.argmax, en yavaş yöntemdir ve dizi kayan nokta veya tamsayı yerine dize içeriyorsa yanlış yanıt verir.
tommy.carstensen

9
Yinelenen maksimum değerler varsa list.index () sorunu olmaz mı?
Logan Yang

20

Bu yanıt, listenin çok büyük olduğu ve zaten bir np.array () olduğu varsayılarak @ Escualo'dan 33 kat daha hızlıdır. Test sayısını azaltmak zorunda kaldım çünkü test sadece 100 değil 10000000 elemente bakıyor.

import random
from datetime import datetime
import operator
import numpy as np

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

def npmax(l):
    max_idx = np.argmax(l)
    max_val = l[max_idx]
    return (max_idx, max_val)

if __name__ == "__main__":
    from timeit import Timer

t = Timer("npmax(l)", "from __main__ import explicit, implicit, npmax; "
      "import random; import operator; import numpy as np;"
      "l = np.array([random.random() for _ in xrange(10000000)])")
print "Npmax: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Explicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Implicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

Bilgisayarımdaki sonuçlar:

Npmax: 8.78 msec/pass
Explicit: 290.01 msec/pass
Implicit: 790.27 msec/pass

Açıklığa kavuşturmak için: hızlandırma sadece saf Python'a karşı numpy C uygulamasından mı kaynaklanıyor? Ya da @ Escualo'nun saf python kullanarak cevabını geliştirmenin bir yolu var mı?
en fazla

Biri python 3.6 kullanmak istiyorsa, şöyle bir şey yapabilir: "l = np.array ([random.random () için _ aralığında (10000000)]))") yazdır (f "Npmax: {(1000 * t. timeit (sayı = 10) / 10): 5,2f} msn / geçiş ")
Piotr Siejda


1
Peki, standart bir python listesini işleyene numpy.argmaxkadar şaşırtıcı görünüyor . Sonra hız, açık ve kapalı sürüm arasındadır. Sanırım sadece bir liste oluşturmakla kalmaz, aynı zamanda bazı ekstra bilgileri de kaydeder - örneğin min ve max değerleri (sadece bir hipotez). np.array
Miroslaw Opoka

18

Python'un yerleşik kütüphanesi ile oldukça kolay:

a = [2, 9, -10, 5, 18, 9] 
max(xrange(len(a)), key = lambda x: a[x])

Bu söyler maxlistesindeki en büyük sayısını bulmak için [0, 1, 2, ..., len(a)]özel bir işlevi kullanarak, lambda x: a[x]diyor, 0aslında 2, 1aslında 9, vb


Python 3'te xrange yoktur, hem Python 2 hem de Python 3 için çalışacak kod yazmak istiyorsanız range () öğesini kullanmalısınız.
Chunde Huang

10
max([(v,i) for i,v in enumerate(my_list)])

Bu daha iyidir çünkü tuple dışında bir şeyle kullanmak için uyarlayabilirsiniz.
wieczorek1990

Bu tam olarak nasıl çalışıyor? Süreci parçalayabilir misin?
clabe45

Merhaba @ clabe45, bu v_ listemin her öğe ve i karşılık gelen dizin olduğu tuples (v, i) bir listede my_list dönüştürür, sonra maximun değeri (ve ilişkili dizini ile de) tuple alır
Luis Sobrecueva

4
Teşekkürler, muhtemelen cevaba gönderebilir misiniz? Ve maksimum değeri hesaplarken maxher bir tupledaki ( v) ilk öğeyi dikkate almayı nasıl bilebilirsiniz ?
clabe45

1
@ clabe45 Bu yanıt çok geç olabilir, ancak şimdi bu konuya rastlayan diğerleri için (benim gibi) burada: stackoverflow.com/questions/18296755/… bir açıklamadır. Bu satır değil: "Varsayılan olarak max, öğeleri ilk dizine göre karşılaştıracaktır; ilk dizin aynıysa ikinci dizini karşılaştırır." Bu yüzden listeyi denedim: l = [1,1,1] ve sonra max ([(v, i) i için, enumerate (l)] de v)) ve bana ilk 1 değil sonuncusu bir: sonuç olarak (1,2). Umarım açıklar :)
Anupam Jain

10

Çok basit bir yol öneririm:

import numpy as np
l = [10, 22, 8, 8, 11]
print(np.argmax(l))
print(np.argmin(l))

Umarım yardımcı olur.


4
max([(value,index) for index,value in enumerate(your_list)]) #if maximum value is present more than once in your list then this will return index of the last occurrence

Şu anda maksimum değer birden fazla ise ve tüm endeksleri almak istiyorsanız,

max_value = max(your_list)
maxIndexList = [index for index,value in enumerate(your_list) if value==max(your_list)]

1
Evet. Neredeyse bir cevap yayınladım, ama sonra liste çözümünüzde tek satırda aynı mantıkla aynı çözümü bulduğunuzu gördüm.
WalyKu

2

Belki de sıralanmış bir listeye ihtiyacınız var?

Bunu dene:

your_list = [13, 352, 2553, 0.5, 89, 0.4]
sorted_list = sorted(your_list)
index_of_higher_value = your_list.index(sorted_list[-1])

1. Sıralama daha yüksek zaman karmaşıklığına sahiptir. 2. sorted_listdizinleri değil değerleri vardır, bu yüzden işe yaramaz.

1

bu konu canlandırmak için üzgünüm, ama benim yöntem eklemeye değer olduğunu düşündüm.

Bu örnekte 'list' liste adı

list.sort()
print(list[-1])

Bu listede en yüksek değeri kadar kolay basacaktır!

list.sort()listeyi ASCII tablosundaki öğenin değerine göre sıralar, bu nedenle listeyi etkili bir şekilde en düşükten en yükseğe doğru sıralar. Daha sonra kullanarak listedeki son değeri (en büyük sayı olacak) yazdırıyorum print(list[-1]).

Bu yardımcı olur umarım!


5
dizini bu şekilde
bulamıyoruz

-1

İşte Python'un yerleşik işlevlerini kullanarak sorunuza eksiksiz bir çözüm:

# Create the List
numbers = input("Enter the elements of the list. Separate each value with a comma. Do not put a comma at the end.\n").split(",") 

# Convert the elements in the list (treated as strings) to integers
numberL = [int(element) for element in numbers] 

# Loop through the list with a for-loop

for elements in numberL:
    maxEle = max(numberL)
    indexMax = numberL.index(maxEle)

print(maxEle)
print(indexMax)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.