Cara Pythonic untuk menemukan nilai maksimum dan indeksnya dalam daftar?

151

Jika saya ingin nilai maksimum dalam daftar, saya bisa menulis max(List) , tetapi bagaimana jika saya juga membutuhkan indeks nilai maksimum?

Saya dapat menulis sesuatu seperti ini:

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

Tapi itu terlihat membosankan bagi saya.

Dan jika saya menulis:

List.index(max(List))

Maka itu akan mengulangi daftar dua kali.

Apakah ada cara yang lebih baik?

Sunny88
sumber
Apa yang Anda maksud dengan "akan melewati daftar dua kali"? List.index (maks (Daftar)) berfungsi untuk saya.
mwcz
14
@ mwc: Ini akan mengulang daftar sekali untuk menentukan nilai maksimum, kemudian iterate untuk kedua kalinya untuk menemukan indeks dari nilai itu.
10
Bukankah list.index () bermasalah jika ada nilai maks yang digandakan?
Logan Yang
@LoganYang ya mungkin ada dua item dengan nilai yang sama.
Florian
Jika urutannya tidak penting, Anda dapat melakukan sesuatu seperti List.sort () [- 1]
Florian

Jawaban:

186

Ada banyak opsi, misalnya:

import operator
index, value = max(enumerate(my_list), key=operator.itemgetter(1))
Sven Marnach
sumber
2
Ah, saya pernah melihat ini di tempat lain, tetapi saya pikir itu akan mengembalikan hanya satu nilai, bukan tupel.
Sunny88
1
@ Sunny88: keyFungsi ini hanya digunakan untuk memutuskan elemen mana yang maksimal. Elemen tidak berubah.
Sven Marnach
6
@SvenMarnach Mengapa tidak key=lambda e: e[1]dan karenanya menghindari impor?
lifebalance
8
@lifebalance Menggunakan itemgetter()lebih cepat, dan menghindari impor bukanlah tujuan yang layak dikejar. Menghindari ketergantungan eksternal dapat bermanfaat dalam beberapa kasus, tetapi impor dari perpustakaan standar adalah masalah.
Sven Marnach
324

Saya pikir jawaban yang diterima bagus, tetapi mengapa Anda tidak melakukannya secara eksplisit? Saya merasa lebih banyak orang akan memahami kode Anda, dan itu sesuai dengan PEP 8:

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

Metode ini juga sekitar tiga kali lebih cepat daripada jawaban yang diterima:

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)

Hasil saat dijalankan di komputer saya:

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

Set lainnya:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass
Escualo
sumber
3
Tidak berharap itu menjadi lebih cepat. Lebih cepat bahkan ketika saya mengganti l dengan "l = [random.random () untuk _ in xrange (10000000)] + [2]", yang menjamin bahwa elemen terakhir adalah yang terbesar.
Sunny88
14
@ Sunny88: Untuk daftar angka sederhana, pendekatan sederhana lebih cepat. Jika Anda mencari kinerja dalam hal ini, saya sarankan untuk menggunakannya numpy.argmax(), yang merupakan 30 kali lebih cepat pada mesin saya. Jika daftar berisi objek yang lebih rumit dari sekadar angka, pendekatan dalam jawaban saya bisa menjadi lebih cepat. Keuntungan lain dari pendekatan itu adalah dapat digunakan untuk iterator yang sewenang-wenang, tidak hanya untuk daftar.
Sven Marnach
@ Sven-Marnach Apakah numpy akan lebih cepat, jika saya harus mengubah daftar saya menjadi array numpy terlebih dahulu? Apakah lebih cepat untuk contoh sederhana [0,1,0]?
tommy.carstensen
1
@ Sven-Marnach saya baru saja memeriksa. numpy.argmax sejauh ini merupakan metode yang paling lambat, dan ini memberikan jawaban yang salah, jika array berisi string bukan float atau integer.
tommy.carstensen
9
Bukankah list.index () bermasalah jika ada nilai maks yang digandakan?
Logan Yang
20

Jawaban ini 33 kali lebih cepat dari @Escualo dengan anggapan bahwa daftarnya sangat besar, dan dengan asumsi bahwa itu sudah menjadi np.array (). Saya harus menolak jumlah uji coba karena tes ini melihat 10.000.000 elemen bukan hanya 100.

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 )

Hasil di komputer saya:

Npmax: 8.78 msec/pass
Explicit: 290.01 msec/pass
Implicit: 790.27 msec/pass
portforwardpodcast
sumber
Hanya untuk memperjelas: percepatan hanya karena implementasi C numpy versus python murni? Atau ada cara untuk mendapatkan peningkatan pada jawaban @ Escualo menggunakan python murni?
maks
Jika seseorang ingin menggunakan python 3.6 orang dapat melakukan sesuatu seperti: "l = np.array ([random.random () untuk _ dalam kisaran (10000000)])") mencetak (f "Npmax: {(1000 * t. timeit (angka = 10) / 10): 5.2f} msec / pass ")
Piotr Siejda
Ini pada 2.7
portforwardpodcast
1
Nah, kecepatan numpy.argmaxtampilannya luar biasa sampai Anda membiarkannya memproses daftar python standar . Kemudian kecepatan terletak di antara versi eksplisit dan implisit. Saya kira np.arraytidak hanya membuat daftar tetapi menyimpan beberapa info tambahan di dalamnya - seperti misalnya nilai min dan maks (hanya hipotesis).
Miroslaw Opoka
18

Dengan perpustakaan bawaan Python, sangat mudah:

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

Ini memberitahu Anda maxuntuk menemukan nomor terbesar dalam daftar [0, 1, 2, ..., len(a)], menggunakan fungsi kustom lambda x: a[x], yang mengatakan itu 0sebenarnya 2, 1sebenarnya 9, dll.

Sunil Kapil
sumber
Di Python 3, tidak ada xrange, jika Anda ingin menulis kode yang akan berjalan untuk Python 2 dan Python 3, Anda harus menggunakan range ().
Chunde Huang
10
max([(v,i) for i,v in enumerate(my_list)])
Luis Sobrecueva
sumber
Ini lebih baik karena Anda dapat mengadaptasinya untuk digunakan dengan sesuatu selain tuple.
wieczorek1990
Bagaimana tepatnya cara kerjanya? Bisakah Anda memecah prosesnya?
clabe45
Hai @ clabe45, ini mengonversi my_list dalam daftar tupel (v, i) di mana v adalah setiap item dalam daftar saya dan saya adalah indeks koresponden, kemudian mendapatkan tuple dengan nilai maximun (dan dengan indeks yang terkait juga)
Luis Sobrecueva
4
Terima kasih, bisakah Anda mempostingnya dalam jawaban? Dan bagaimana cara maxmengetahui untuk mengambil item pertama dari setiap tuple ( v) ke dalam perhitungan saat menghitung nilai maksimum?
clabe45
1
@ clabe45 Mungkin jawaban ini terlambat, tetapi untuk orang lain (seperti saya) yang menemukan utas ini sekarang, di sini: stackoverflow.com/questions/18296755/… adalah sebuah penjelasan. Bukan baris ini: "Secara default max akan membandingkan item dengan indeks pertama, jika indeks pertama sama maka itu akan membandingkan indeks kedua." Jadi saya mencobanya dengan daftar: l = [1,1,1] dan kemudian maks ([(v, i) untuk saya, v dalam penghitungan (l)]) dan itu memberi saya bukan yang pertama tetapi yang terakhir satu: (1,2) sebagai hasilnya. Saya harap ini menjelaskan :)
Anupam Jain
10

Saya akan menyarankan cara yang sangat sederhana:

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

Semoga ini bisa membantu.

Igor Manzhos
sumber
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

Jika nilai maksimum hadir lebih dari satu kali dan Anda ingin mendapatkan semua indeks,

max_value = max(your_list)
maxIndexList = [index for index,value in enumerate(your_list) if value==max(your_list)]
Islam Taohidul
sumber
1
Ya. Saya hampir memposting jawaban, tetapi kemudian saya melihat Anda sudah memiliki solusi yang sama dengan logika yang sama dalam daftar pemahaman Anda satu-liner.
WalyKu
2

Mungkin Anda perlu daftar yang disortir?

Coba ini:

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])
Mattias
sumber
1. Penyortiran memiliki kompleksitas waktu yang lebih tinggi. 2. sorted_listbelum indeks tetapi nilai, jadi itu tidak akan berhasil.
1

maaf telah menghidupkan kembali utas ini, tetapi menganggap metode saya layak ditambahkan.

Nama daftar dalam contoh ini 'daftar'

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

Itu akan mencetak nilai tertinggi dalam daftar semudah!

list.sort()mengurutkan daftar berdasarkan nilai item dalam tabel ASCII , jadi secara efektif mengurutkan daftar terendah ke tertinggi. Saya kemudian hanya mencetak nilai terakhir dalam daftar (yang akan menjadi angka terbesar) dengan menggunakanprint(list[-1]) .

Semoga ini membantu!

Mackey Johnstone
sumber
5
kita tidak bisa mendapatkan indeks dengan cara ini
toing_toing
-1

Berikut ini adalah solusi lengkap untuk pertanyaan Anda menggunakan fungsi bawaan Python:

# 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)
Samdom For Peace
sumber