วิธี Pythonic เพื่อหาค่าสูงสุดและดัชนีในรายการ?


151

ถ้าฉันต้องการค่าสูงสุดในรายการฉันสามารถเขียนmax(List)ได้ แต่ถ้าฉันต้องการดัชนีค่าสูงสุดด้วยล่ะ

ฉันสามารถเขียนสิ่งนี้:

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

แต่มันดูน่าเบื่อสำหรับฉัน

และถ้าฉันเขียน:

List.index(max(List))

จากนั้นจะวนซ้ำรายการสองครั้ง

มีวิธีที่ดีกว่า?


คุณหมายถึงอะไรโดย "จะผ่านรายการสองครั้ง" List.index (สูงสุด (รายการ)) ใช้งานได้สำหรับฉัน
mwcz

14
@mwc: มันจะวนซ้ำรายการหนึ่งครั้งเพื่อกำหนดค่าสูงสุดแล้ววนซ้ำเป็นครั้งที่สองเพื่อค้นหาดัชนีของค่านั้น

10
list.index () จะไม่เป็นปัญหาหากมีค่าสูงสุดซ้ำกันหรือไม่
Logan Yang

@LoganYang ใช่อาจมีสองรายการที่มีค่าเหมือนกัน
Florian

หากคำสั่งซื้อไม่สำคัญคุณสามารถทำอะไรเช่น List.sort () [- 1]
Florian

คำตอบ:


186

มีตัวเลือกมากมายเช่น:

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

2
อาฉันได้เห็นสิ่งนี้ในที่อื่น แต่ฉันคิดว่ามันจะคืนค่าเพียงค่าเดียวไม่ใช่สิ่งอันดับ
Sunny88

1
@ Sunny88: keyฟังก์ชั่นนี้ใช้เพื่อตัดสินใจว่าองค์ประกอบใดจะสูงสุด องค์ประกอบจะไม่เปลี่ยนแปลง
Sven Marnach

6
@SvenMarnach ทำไมไม่ลองkey=lambda e: e[1]แทนดังนั้นจึงหลีกเลี่ยงการนำเข้า
อายุการใช้งาน

8
@ Lifebalance การใช้itemgetter()เร็วกว่าและการหลีกเลี่ยงการนำเข้าไม่ใช่เป้าหมายที่ควรดำเนินการ การหลีกเลี่ยงการพึ่งพาจากภายนอกอาจคุ้มค่าในบางกรณี แต่การนำเข้าจากไลบรารีมาตรฐานนั้นไม่ใช่ปัญหา
Sven Marnach

324

ฉันคิดว่าคำตอบที่ยอมรับนั้นยอดเยี่ยม แต่ทำไมคุณไม่ทำอย่างชัดเจน? ฉันรู้สึกว่ามีคนอีกมากที่จะเข้าใจโค้ดของคุณและนั่นเป็นข้อตกลงกับ PEP 8:

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

วิธีนี้เร็วกว่าคำตอบที่ยอมรับประมาณสามเท่า:

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)

ผลลัพธ์ตามที่ทำงานในคอมพิวเตอร์ของฉัน:

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

ชุดอื่น ๆ :

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

3
ไม่ได้คาดหวังว่ามันจะเร็วขึ้น มันเร็วกว่าแม้ว่าฉันจะแทนที่ l ด้วย "l = [random.random () สำหรับ _ in xrange (10,000000)] + [2]" ซึ่งรับประกันได้ว่าองค์ประกอบสุดท้ายจะใหญ่ที่สุด
Sunny88

14
@ Sunny88: สำหรับรายการตัวเลขแบบง่ายวิธีการที่ง่ายกว่าจะเร็วกว่า หากคุณอยู่หลังการแสดงในกรณีนี้ฉันแนะนำให้ใช้numpy.argmax()ซึ่งเร็วกว่าเครื่องของฉันอีก 30 เท่า หากรายการมีวัตถุที่ซับซ้อนมากกว่าตัวเลขเพียงวิธีการในคำตอบของฉันจะกลายเป็นเร็วขึ้น ข้อดีอีกประการของวิธีการนี้คือสามารถใช้สำหรับตัววนซ้ำแบบกำหนดเองไม่เฉพาะสำหรับรายการเท่านั้น
Sven Marnach

@ Sven-Marnach ฉันจะต้องเร็วกว่านี้ไหมถ้าฉันต้องแปลงรายการของฉันให้เป็นแถวแรก? มันจะเร็วกว่าสำหรับตัวอย่างง่ายๆ [0,1,0] ไหม
tommy.carstensen

1
@ Sven-Marnach ฉันเพิ่งตรวจสอบ numpy.argmax เป็นวิธีที่ช้าที่สุดและให้คำตอบที่ไม่ถูกต้องหากอาร์เรย์มีสตริงแทนที่จะลอยหรือจำนวนเต็ม
tommy.carstensen

9
list.index () จะไม่เป็นปัญหาหากมีค่าสูงสุดซ้ำกันหรือไม่
Logan Yang

20

คำตอบนี้เร็วกว่า @Escualo 33 เท่าโดยสมมติว่ารายการมีขนาดใหญ่มากและสมมติว่าเป็น np.array () ฉันต้องลดจำนวนการทดสอบลงเนื่องจากการทดสอบดูที่องค์ประกอบ 10,000,000 ไม่ใช่แค่ 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 )

ผลลัพธ์ในคอมพิวเตอร์ของฉัน:

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

เพื่อชี้แจง: การเร่งความเร็วนั้นเกิดจากการนำ C ไปใช้กับ numpy pure เท่านั้น? หรือมีวิธีใดที่จะปรับปรุงคำตอบของ @ Escualo โดยใช้ python บริสุทธิ์
สูงสุด

ถ้าใครอยากใช้ python 3.6 ก็สามารถทำได้เช่น: "l = np.array ([random.random () สำหรับ _ ในช่วง (10,000000)])") พิมพ์) (f "Npmax: {(1000 * t) timeit (หมายเลข = 10) / 10): 5.2f} msec / pass ")
Piotr Siejda

นี่คือวันที่ 2.7
portforwardpodcast

1
ความเร็วในการnumpy.argmaxดูน่าอัศจรรย์จนกระทั่งคุณปล่อยให้มันประมวลผลรายการไพ ธ อนมาตรฐาน จากนั้นความเร็วจะอยู่ระหว่างเวอร์ชันที่ชัดเจนและโดยนัย ฉันเดาnp.arrayว่าไม่ได้แค่สร้างรายการ แต่มันจะบันทึกข้อมูลพิเศษบางอย่างในนั้น - เช่นค่า min และ max (แค่สมมุติฐาน)
Miroslaw Opoka

18

ด้วยห้องสมุดในตัวของ Python มันค่อนข้างง่าย:

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

นี้จะบอกmaxว่าจะหาจำนวนมากที่สุดในรายการ[0, 1, 2, ..., len(a)]โดยใช้ฟังก์ชั่นที่กำหนดเองlambda x: a[x]ซึ่งบอกว่า0เป็นจริง2, 1เป็นจริง9ฯลฯ


ใน Python 3 ไม่มี xrange หากคุณต้องการเขียนโค้ดที่จะทำงานสำหรับทั้ง Python 2 และ Python 3 คุณควรใช้ range ()
Chunde Huang

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

นี้จะดีกว่าเพราะคุณสามารถปรับให้ใช้กับสิ่งอื่นที่ไม่ใช่ tuple
wieczorek1990

มันทำงานยังไงกันแน่? คุณสามารถทำลายกระบวนการได้หรือไม่?
clabe45

สวัสดี @ clabe45 มันจะแปลง my_list ในรายการของ tuples (v, i) โดยที่ v คือทุกรายการในรายการของฉันและฉันคือดัชนีผู้ติดต่อจากนั้นมันจะได้รับ tuple ด้วยค่าสูงสุด (และด้วยดัชนีที่เกี่ยวข้องด้วย)
Luis Sobrecueva

4
ขอบคุณคุณสามารถโพสต์สิ่งนั้นด้วยคำตอบได้ไหม? และจะmaxรู้ได้อย่างไรว่านำไอเท็มแรกของทุก tuple ( v) เข้ามาในการคำนวณค่าสูงสุด?
clabe45

1
@ clabe45 อาจเป็นคำตอบนี้มาช้าเกินไป แต่สำหรับคนอื่น ๆ (เช่นฉัน) ที่เคยเจอเธรดนี้ตอนนี้ที่นี่: stackoverflow.com/questions/18296755/…เป็นคำอธิบาย ไม่ใช่บรรทัดนี้: "โดยค่าเริ่มต้นสูงสุดจะเปรียบเทียบรายการตามดัชนีแรกถ้าดัชนีแรกเหมือนกันมันจะเปรียบเทียบดัชนีที่สอง" ดังนั้นฉันจึงลองทำรายการ: l = [1,1,1] จากนั้น max ([(v, i) สำหรับ i, v ใน enumerate (l)]) และมันไม่ใช่ 1 ตัวแรก แต่สุดท้าย หนึ่ง: (1,2) เป็นผลลัพธ์ ฉันหวังว่ามันจะอธิบาย :)
Anupam Jain

10

ฉันขอแนะนำวิธีง่าย ๆ :

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

หวังว่ามันจะช่วย


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

หากมูลค่าสูงสุดในปัจจุบันมากกว่าหนึ่งครั้งและคุณต้องการรับดัชนีทั้งหมด

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

1
ได้. ฉันเกือบจะโพสต์คำตอบ แต่แล้วฉันเห็นว่าคุณมีวิธีการแก้ปัญหาเดียวกันกับตรรกะเดียวกันในรายการของคุณเข้าใจหนึ่งซับ
WalyKu

2

บางทีคุณอาจต้องการรายการที่เรียงลำดับใช่ไหม

ลองสิ่งนี้:

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. การเรียงลำดับมีความซับซ้อนของเวลาสูงกว่า 2. sorted_listยังไม่ได้จัดทำดัชนี แต่มีค่าดังนั้นมันจะไม่ทำงาน

1

ขออภัยที่ฟื้นฟูหัวข้อนี้ แต่คิดว่าวิธีการของฉันคุ้มค่า

ชื่อรายการในตัวอย่างนี้ 'รายการ'

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

ที่จะพิมพ์ค่าสูงสุดในรายการง่าย ๆ !

list.sort()เรียงลำดับรายการตามค่าของรายการในตาราง ASCIIดังนั้นเรียงลำดับรายการต่ำสุดถึงสูงสุดอย่างมีประสิทธิภาพ จากนั้นผมก็เพียงแค่พิมพ์ค่าสุดท้ายในรายการ (ซึ่งจะมีจำนวนมากที่สุด) print(list[-1])โดยใช้

หวังว่านี่จะช่วยได้!


5
เราไม่สามารถรับดัชนีด้วยวิธีนี้
toing_toing

-1

นี่เป็นคำตอบที่สมบูรณ์สำหรับคำถามของคุณโดยใช้ฟังก์ชั่นในตัวของ 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.