รับดัชนีของรายการ max หรือ mined คืนโดยใช้ max () / min () ในรายการ


465

ฉันใช้งูใหญ่maxและminฟังก์ชั่นในรายการสำหรับขั้นตอนวิธีการ Minimax และฉันต้องดัชนีของค่าที่ส่งกลับโดยหรือmax() min()กล่าวอีกนัยหนึ่งฉันต้องรู้ว่าการเคลื่อนไหวใดที่ทำให้เกิดค่าสูงสุด (ตามเทิร์นของผู้เล่นคนแรก) หรือค่า min (ผู้เล่นคนที่สอง)

for i in range(9):
    newBoard = currentBoard.newBoardWithMove([i / 3, i % 3], player)

    if newBoard:
        temp = minMax(newBoard, depth + 1, not isMinLevel)  
        values.append(temp)

if isMinLevel:
    return min(values)
else:
    return max(values)

ฉันต้องสามารถส่งคืนดัชนีจริงของค่า min หรือ max ไม่ใช่ค่า


32
builtin divmodมีอยู่เพื่อป้องกันไม่ให้พูด[i / 3, i % 3]มาก
Mike Graham

คำตอบ:


416
ถ้า isMinLevel:
    return values.index (นาที (ค่า))
อื่น:
    ส่งคืนค่าดัชนี (สูงสุด (ค่า))

38
@KevinGriffin โปรดทราบว่าสิ่งนี้จะทำให้คุณได้รับโอกาสเกิดขึ้นน้อยที่สุด / มากที่สุด นี่อาจไม่ใช่สิ่งที่คุณต้องการตัวอย่างเช่นหากเป็นไปได้ที่จะเพิ่มกำไรของคุณในสองวิธีเดียวกัน แต่หนึ่งในนั้นทำให้ผู้เล่นคนอื่นเจ็บกว่า ฉันไม่ทราบว่าเป็นกรณีที่คุณต้องพิจารณา
Mike Graham

89
@Kashyap จริงๆแล้ว O (N) ไม่ใช่ O (N ^ 2) ในกรณีขั้นต่ำนาทีแรก (ค่า) จะได้รับการประเมินซึ่งก็คือ O (N) จากนั้นเรียกว่า values.index () ซึ่งก็คือ O (N) O (N) + O (N) = O (N) อาร์กิวเมนต์ไปยังดัชนีจะถูกประเมินเพียงครั้งเดียว มันเทียบเท่ากับ:tmp = min(values); return values.index(tmp)
Tom Karzes

@ มากเกินไป php จะทำอย่างไรเมื่อมีการทำซ้ำขององค์ประกอบ?
Shashi Tunga

@ShashiTunga [รายการ] .index () ส่งคืนเฉพาะการปรากฏครั้งแรกของบางสิ่งเท่านั้นไม่รับประกันว่าเป็นเอกสิทธิ์เฉพาะค่าต่ำสุดอาจไม่ซ้ำในรายการ
Scott Anderson

471

สมมติว่าคุณมีรายการvalues = [3,6,1,5]และต้องการดัชนีขององค์ประกอบที่เล็กที่สุดเช่นindex_min = 2ในกรณีนี้

หลีกเลี่ยงการแก้ปัญหาด้วยitemgetter()การนำเสนอในคำตอบอื่น ๆ และใช้แทน

index_min = min(range(len(values)), key=values.__getitem__)

เพราะมันไม่จำเป็นต้องที่จะimport operatorไม่ให้การใช้งานenumerateและมันก็มักจะได้เร็วขึ้น (มาตรฐานด้านล่าง) itemgetter()มากกว่าการแก้ปัญหาโดยใช้

หากคุณกำลังจัดการกับอาร์เรย์ numpy หรือสามารถจ่ายnumpyเป็นอ้างอิงให้พิจารณาใช้

import numpy as np
index_min = np.argmin(values)

สิ่งนี้จะเร็วกว่าโซลูชันแรกแม้ว่าคุณจะใช้กับรายการ Python อย่างสมบูรณ์หาก:

  • มันมีขนาดใหญ่กว่าองค์ประกอบสองสามชิ้น (ประมาณ 2 ** 4 องค์ประกอบในเครื่องของฉัน)
  • คุณสามารถจ่ายสำเนาหน่วยความจำจากรายการบริสุทธิ์ไปยังnumpyอาร์เรย์

ตามมาตรฐานนี้ชี้ให้เห็น: ป้อนคำอธิบายรูปภาพที่นี่

ฉันใช้มาตรฐานในเครื่องของฉันด้วย python 2.7 สำหรับโซลูชันทั้งสองข้างต้น (สีน้ำเงิน: pure python, โซลูชันแรก) (สีแดง, โซลูชัน numpy) และสำหรับโซลูชันมาตรฐานที่อ้างอิงจากitemgetter()(โซลูชันสีดำอ้างอิง) เกณฑ์มาตรฐานเดียวกันกับ python 3.5 แสดงให้เห็นว่าวิธีการเปรียบเทียบที่เหมือนกันของกรณี python 2.7 ที่นำเสนอข้างต้น


+1 ที่แข็งแกร่งมาก ฉันชอบการเปรียบเทียบการแก้ปัญหาที่เสนอและกฎง่ายๆที่คุณได้สรุป ตามที่ฉันแนะนำในคำตอบอื่นด้านล่างคุณสามารถระบุ (หรือลิงก์ไปยัง) รหัสทดสอบของคุณเพื่อที่คนอื่นอาจทำซ้ำผลลัพธ์ของคุณหรือไม่ เครื่องจักรและห้องสมุดมีการเปลี่ยนแปลงอยู่ตลอดเวลาและจะช่วยให้เปรียบเทียบกับโซลูชันอื่น ๆ
Rakurai

3
ฉันคิดว่าอาจมีการพิมพ์ผิด: xrange มันไม่ควรจะเป็นช่วง?
Lindsay Fowler

6
@LindsayFowler xrange()เลิกใช้แล้วในขณะนี้คุณสามารถใช้range()
davide

np.argmin ไม่ทำงานกับการลอย ข้อเสนอแนะแรกเท่านั้นที่ทำงานกับ ints และลอย
jimh

import numpy as np; x = [2.3, -1.4]; np.argmin(x)ผมคิดว่าคุณจะเข้าใจผิดลอง คุณจะเห็นว่ามันargminใช้กับลอยได้เช่นกัน
gg349

332

คุณสามารถค้นหาดัชนีขั้นต่ำ / สูงสุดและค่าในเวลาเดียวกันหากคุณระบุรายการในรายการ แต่ดำเนินการขั้นต่ำ / สูงสุดในค่าเริ่มต้นของรายการ ชอบมาก

import operator
min_index, min_value = min(enumerate(values), key=operator.itemgetter(1))
max_index, max_value = max(enumerate(values), key=operator.itemgetter(1))

วิธีนี้รายการจะถูกสำรวจภายในหนึ่งครั้งสำหรับ min (หรือสูงสุด)


110
หรือใช้แลมบ์ดา:key=lambda p: p[1]
Scry

116

หากคุณต้องการหาดัชนี max ภายในรายการตัวเลข (ซึ่งดูเหมือนว่าเป็นกรณีของคุณ) ฉันขอแนะนำให้คุณใช้ numpy:

import numpy as np
ind = np.argmax(mylist)

ในกรณีที่เกิดขึ้นหลายครั้งของค่าสูงสุดดัชนีที่สอดคล้องกับการเกิดขึ้นครั้งแรกจะถูกส่งกลับ
Cohensius

41

อาจเป็นวิธีที่ง่ายกว่าในการเปลี่ยนอาเรย์ของค่าให้เป็นอาเรย์ของค่าดัชนีคู่และรับค่าสูงสุด / นาที สิ่งนี้จะให้ดัชนีที่ใหญ่ที่สุด / เล็กที่สุดที่มีค่าสูงสุด / นาที (เช่นคู่จะถูกเปรียบเทียบโดยการเปรียบเทียบองค์ประกอบแรกก่อนจากนั้นเปรียบเทียบองค์ประกอบที่สองหากองค์ประกอบแรกเหมือนกัน) โปรดทราบว่าไม่จำเป็นต้องสร้างอาร์เรย์จริงเพราะ min / max อนุญาตให้เครื่องกำเนิดเป็นอินพุต

values = [3,4,5]
(m,i) = max((v,i) for i,v in enumerate(values))
print (m,i) #(5, 2)


18

ฉันคิดว่าสิ่งที่ดีที่สุดที่ต้องทำคือแปลงรายการเป็น a numpy arrayและใช้ฟังก์ชันนี้:

a = np.array(list)
idx = np.argmax(a)

14

ฉันสนใจสิ่งนี้และเปรียบเทียบโซลูชันที่แนะนำโดยใช้perfplot (โครงการสัตว์เลี้ยงของฉัน)

ปรากฎว่าargmin ของ numpy ,

numpy.argmin(x)

เป็นวิธีที่เร็วที่สุดสำหรับรายการขนาดใหญ่พอที่แม้จะมีการแปลงนัยจากการป้อนข้อมูลไปยังlistnumpy.array

ป้อนคำอธิบายรูปภาพที่นี่


รหัสสำหรับการสร้างพล็อต:

import numpy
import operator
import perfplot


def min_enumerate(a):
    return min(enumerate(a), key=lambda x: x[1])[0]


def min_enumerate_itemgetter(a):
    min_index, min_value = min(enumerate(a), key=operator.itemgetter(1))
    return min_index


def getitem(a):
    return min(range(len(a)), key=a.__getitem__)


def np_argmin(a):
    return numpy.argmin(a)


perfplot.show(
    setup=lambda n: numpy.random.rand(n).tolist(),
    kernels=[
        min_enumerate,
        min_enumerate_itemgetter,
        getitem,
        np_argmin,
        ],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    )

ขอให้สังเกตว่าข้อสรุปเดียวกันถูกโพสต์ไว้ข้างต้นแล้วในคำตอบของฉันมากกว่า 2 ปีที่แล้วพร้อมข้อมูลเพิ่มเติมเกี่ยวกับเวลาและเหตุผลที่สามารถใช้อาร์กิวเมนต์ได้หรือไม่ ลองลบคำตอบซึ่งไม่ได้เป็นการทำบุญในสิ่งที่เสนอไปแล้วในหน้าเดียวกันนี้ ลองพิจารณาทบทวนคำตอบอื่น ๆ ของคุณเกี่ยวกับ SO เพื่อให้มีพฤติกรรมที่คล้ายกัน: คุณดูเหมือนจะไม่ได้อ้างถึงคำตอบจริง ๆ ที่ให้ทางออกที่ดีที่สุดในการวิเคราะห์ประสิทธิภาพของคุณ มันค่อนข้างจะแย่โดยเฉพาะอย่างยิ่งสำหรับคนที่มีตัวแทนมากกว่า 10K ที่รู้จักมานานกว่านั้น
gg349

@ gg349 จุดที่ดีมาก แต่เขาให้รหัสแหล่งที่มาสำหรับการสร้างผลลัพธ์ทำให้สิ่งนี้ทำซ้ำได้ง่ายและปรับให้เข้ากับการเปรียบเทียบโซลูชันอื่น ๆ ฉันยอมรับว่าเขาอาจพิจารณาลบคำตอบนี้ซ้ำซ้อน แต่บางทีคุณสามารถเพิ่มมูลค่าให้กับคำตอบของคุณโดยการรวมหรือเชื่อมโยงกับรหัสที่คุณใช้?
Rakurai


8

หลังจากที่คุณได้รับค่าสูงสุดลองสิ่งนี้:

max_val = max(list)
index_max = list.index(max_val)

ง่ายกว่าตัวเลือกมากมาย


6

ฉันคิดว่าคำตอบข้างต้นแก้ปัญหาของคุณได้ แต่ฉันคิดว่าฉันจะแบ่งปันวิธีการที่จะช่วยให้คุณมีดัชนีขั้นต่ำและดัชนีขั้นต่ำทั้งหมดจะปรากฏขึ้น

minval = min(mylist)
ind = [i for i, v in enumerate(mylist) if v == minval]

รายการนี้ผ่านสองครั้ง แต่ก็ยังค่อนข้างเร็ว อย่างไรก็ตามมันช้ากว่าการค้นหาดัชนีของการเผชิญหน้าครั้งแรกเล็กน้อย ดังนั้นหากคุณต้องการเพียงหนึ่งในขั้นต่ำสุดให้ใช้วิธีแก้ปัญหาของMatt Andersonหากคุณต้องการทุกอย่างใช้สิ่งนี้


1
ฉันชอบสิ่งนี้เพราะมันใช้ฐาน Python และฉันเข้าใจว่ารายการเข้าใจง่ายกว่า itemgetter แลมบ์ดา ฯลฯ (และมีความยืดหยุ่นพอที่จะแก้ปัญหาต่าง ๆ ของงานเช่นนี้ .... )
James

ดิบ. ฉันชอบสิ่งนี้
Dev_Man

6

ใช้ฟังก์ชั่นโมดูล numpy ที่ใดก็ได้

import numpy as n
x = n.array((3,3,4,7,4,56,65,1))

สำหรับดัชนีค่าต่ำสุด:

idx = n.where(x==x.min())[0]

สำหรับดัชนีมูลค่าสูงสุด:

idx = n.where(x==x.max())[0]

ในความเป็นจริงฟังก์ชั่นนี้มีประสิทธิภาพมากขึ้น คุณสามารถสร้างการดำเนินการบูลีนทุกชนิดสำหรับดัชนีที่มีค่าระหว่าง 3 ถึง 60:

idx = n.where((x>3)&(x<60))[0]
idx
array([2, 3, 4, 5])
x[idx]
array([ 4,  7,  4, 56])

ดัชนีใน python เริ่มต้นที่ 0 ดัชนีที่ส่งคืนจะเป็น 6 (สำหรับ 65) ในขณะที่รหัสของคุณส่งคืน 7 (คำถามของ OP คือ "การรับดัชนี ... ")
tagoma

ในคำสั่งฉันได้สอบถามดัชนีของค่าต่ำสุด (ที่นี่: 1) ซึ่งดัชนีคือ 7. 65 คือค่าสูงสุดขององค์ประกอบในอาร์เรย์ หากคุณพิมพ์: n.where (x == x.max ()) [0] คุณจะได้รับดัชนีสูงสุด ค่าซึ่งคือ 65 ที่นี่ ดัชนีของมันจะออกมาเป็น 6
Ishan Tomar

การใช้งานของ numpy: อาจห้ามในแอปพลิเคชันนี้ แต่ถ้าคุณจะใช้ numpy คุณจะดีขึ้นกว่าargmin()ที่คุณใช้แทนที่จะทำที่นี่
RBF06

ขอบคุณ @ RBF06 ฉันจะลองดูนะ
Ishan Tomar

5

นี่เป็นไปได้เพียงแค่ใช้ในตัวenumerate()และmax()ฟังก์ชั่นและkeyอาร์กิวเมนต์ที่เป็นตัวเลือกของmax()ฟังก์ชั่นและการแสดงออกแลมบ์ดาที่เรียบง่าย:

theList = [1, 5, 10]
maxIndex, maxValue = max(enumerate(theList), key=lambda v: v[1])
# => (2, 10)

ในเอกสารmax()มันบอกว่าkeyอาร์กิวเมนต์คาดหวังว่าฟังก์ชั่นเช่นเดียวกับในlist.sort()ฟังก์ชั่น ยังเห็นการเรียงลำดับวิธีการ

min()มันทำงานได้เหมือนกันสำหรับ Btw จะส่งคืนค่าสูงสุด / นาทีแรก


ช้า แต่คำตอบที่ดีที่สุด (ถ้าคุณไม่ต้องการความเร็ว)
mmj

5

สมมติว่าคุณมีรายการเช่น:

a = [9,8,7]

สองวิธีต่อไปนี้เป็นวิธีที่กะทัดรัดในการรับ tuple พร้อมกับองค์ประกอบขั้นต่ำและดัชนี ทั้งสองใช้เวลาที่คล้ายกันเวลาที่จะดำเนินการ ฉันชอบวิธี zip มากกว่า แต่นั่นคือรสนิยมของฉัน

วิธีการ zip

element, index = min(list(zip(a, range(len(a)))))

min(list(zip(a, range(len(a)))))
(7, 2)

timeit min(list(zip(a, range(len(a)))))
1.36 µs ± 107 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

วิธีการแจกแจง

index, element = min(list(enumerate(a)), key=lambda x:x[1])

min(list(enumerate(a)), key=lambda x:x[1])
(2, 7)

timeit min(list(enumerate(a)), key=lambda x:x[1])
1.45 µs ± 78.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

4

ตราบใดที่คุณรู้วิธีใช้แลมบ์ดาและอาร์กิวเมนต์ "คีย์" โซลูชันที่ง่าย ๆ ก็คือ:

max_index = max( range( len(my_list) ), key = lambda index : my_list[ index ] )

สะอาดมาก! และต่างจากคำตอบที่ยอมรับนี่เป็นจริง O (n) ใช่ไหม ฉันรู้ว่า O (2n) ถือเป็น O (n) แต่สำหรับขนาดใหญ่มากnมันอาจช้าลงอย่างเห็นได้ชัด
kevlarr


3

ทำไมต้องเพิ่มดัชนีก่อนแล้วจึงย้อนกลับ ฟังก์ชัน Enumerate () เป็นเพียงกรณีพิเศษของการใช้ฟังก์ชัน zip () มาใช้ในวิธีที่เหมาะสม:

my_indexed_list = zip(my_list, range(len(my_list)))

min_value, min_index = min(my_indexed_list)
max_value, max_index = max(my_indexed_list)

2

เพียงแค่เพิ่มเล็กน้อยในสิ่งที่พูดไปแล้ว values.index(min(values))ดูเหมือนว่าจะส่งคืนดัชนีที่เล็กที่สุดของนาที ต่อไปนี้ได้รับดัชนีที่ใหญ่ที่สุด:

    values.reverse()
    (values.index(min(values)) + len(values) - 1) % len(values)
    values.reverse()

บรรทัดสุดท้ายสามารถทิ้งไว้ได้หากผลข้างเคียงของการย้อนกลับเข้าที่ไม่สำคัญ

เพื่อย้ำผ่านสิ่งที่เกิดขึ้นทั้งหมด

    indices = []
    i = -1
    for _ in range(values.count(min(values))):
      i = values[i + 1:].index(min(values)) + i + 1
      indices.append(i)

เพื่อความกระชับ อาจเป็นความคิดที่ดีกว่าในการแคชmin(values), values.count(min)นอกลูป


2
reversed(…)แทนที่จะ….reverse()เป็นที่นิยมมากกว่าเพราะมันไม่ได้กลายพันธุ์และส่งกลับเครื่องกำเนิดไฟฟ้าอยู่ดี และเหตุการณ์ทั้งหมดอาจเป็นminv = min(values); indices = [i for i, v in enumerate(values) if v == minv]
HoverHell

2

วิธีง่ายๆในการค้นหาดัชนีที่มีค่าน้อยที่สุดในรายการหากคุณไม่ต้องการนำเข้าโมดูลเพิ่มเติม:

min_value = min(values)
indexes_with_min_value = [i for i in range(0,len(values)) if values[i] == min_value]

จากนั้นเลือกตัวอย่างอันแรก:

choosen = indexes_with_min_value[0]

1

อย่ามีตัวแทนมากพอที่จะแสดงความคิดเห็นคำตอบที่มีอยู่

แต่สำหรับhttps://stackoverflow.com/a/11825864/3920439คำตอบ

สิ่งนี้ใช้ได้กับจำนวนเต็ม แต่ไม่สามารถใช้ได้กับอาร์เรย์ของลอย (อย่างน้อยใน python 3.6) มันจะเพิ่มขึ้น TypeError: list indices must be integers or slices, not float


0

https://docs.python.org/3/library/functions.html#max

หากมีหลายรายการมากที่สุดฟังก์ชันจะคืนค่ารายการแรกที่พบ สิ่งนี้สอดคล้องกับเครื่องมือรักษาความมั่นคงในการเรียงลำดับอื่น ๆ เช่นsorted(iterable, key=keyfunc, reverse=True)[0]

เพื่อให้ได้มากกว่าเพียงแค่ใช้วิธีการเรียงลำดับแรก

import operator

x = [2, 5, 7, 4, 8, 2, 6, 1, 7, 1, 8, 3, 4, 9, 3, 6, 5, 0, 9, 0]

min = False
max = True

min_val_index = sorted( list(zip(x, range(len(x)))), key = operator.itemgetter(0), reverse = min )

max_val_index = sorted( list(zip(x, range(len(x)))), key = operator.itemgetter(0), reverse = max )


min_val_index[0]
>(0, 17)

max_val_index[0]
>(9, 13)

import ittertools

max_val = max_val_index[0][0]

maxes = [n for n in itertools.takewhile(lambda x: x[0] == max_val, max_val_index)]

0

เกี่ยวกับสิ่งนี้:

a=[1,55,2,36,35,34,98,0]
max_index=dict(zip(a,range(len(a))))[max(a)]

มันสร้างพจนานุกรมจากรายการในaฐานะที่เป็นกุญแจและดัชนีของพวกเขาเป็นค่าจึงdict(zip(a,range(len(a))))[max(a)]ส่งกลับค่าที่สอดคล้องกับกุญแจmax(a)ซึ่งเป็นดัชนีของสูงสุดใน ฉันเป็นผู้เริ่มต้นในงูใหญ่ดังนั้นฉันไม่รู้เกี่ยวกับความซับซ้อนในการคำนวณของโซลูชันนี้

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