จะหาตำแหน่งทั้งหมดของค่าสูงสุดในรายการได้อย่างไร


152

ฉันมีรายการ:

a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50,
             35, 41, 49, 37, 19, 40, 41, 31]

องค์ประกอบสูงสุดคือ 55 (สององค์ประกอบในตำแหน่งที่ 9 และ 12)

ฉันต้องการค้นหาตำแหน่งใดที่มีค่าสูงสุดตั้งอยู่ กรุณาช่วย.

คำตอบ:


210
>>> m = max(a)
>>> [i for i, j in enumerate(a) if j == m]
[9, 12]

4
คำตอบสั้น ๆ ที่ดีถ้าคุณไม่รังเกียจที่จะทำหลายรายการผ่านซึ่งเป็นไปได้
martineau

ยกเว้น 0 ใหญ่สำหรับนี่คือ 2n รายการจะวนซ้ำผ่าน 2x หนึ่งครั้งเพื่อกำหนดค่าสูงสุดและอีกครั้งเพื่อค้นหาตำแหน่งของค่าสูงสุด สำหรับลูปที่ติดตามแม็กซ์ปัจจุบันและตำแหน่งอาจมีประสิทธิภาพมากขึ้นสำหรับลิสต์ที่ยาวมาก ๆ
radtek

1
@radtek big O เป็นเพียงแค่ n สัมประสิทธิ์นำจะถูกละเว้นในใหญ่ O
michaelsnowden

1
ในทางทฤษฎี O (N) และ O (2N) เหมือนกัน แต่ในทางปฏิบัติ O (N) จะมีเวลาทำงานที่สั้นลงอย่างแน่นอนโดยเฉพาะเมื่อ N เข้าใกล้อนันต์
radtek

314
a.index(max(a))

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


8
สิ่งนี้จะทำให้คุณได้รับอินสแตนซ์แรกเท่านั้นและเขาขอดัชนีทั้งหมดที่พบค่ามากที่สุด คุณต้องวนซ้ำโดยใช้ชิ้นเพื่อรับรายการที่เหลือในแต่ละกรณีและจัดการข้อยกเว้นเมื่อไม่พบอีกต่อไป
jaydel

10
ฉันพูดถึงว่ามันจะให้ตัวอย่างแรกเท่านั้น หากคุณต้องการทั้งหมดของพวกเขาโซลูชั่นของ SilentGhost นั้นสวยกว่ามากและมีข้อผิดพลาดน้อยกว่า
nmichaels

7
อย่างน้อยตอนที่ฉันมาถึงคำถามจะถามรายชื่ออย่างชัดเจนในกรณีของ maxima หลายตัว ...
emmagras

2
ในทางเทคนิคคุณสามารถใช้สิ่งนี้เพื่อรับอินสแตนซ์แรกขององค์ประกอบที่มีค่ามากที่สุดจากนั้นตั้งค่าเป็นจำนวนลบที่มีค่ามากและจากนั้นหาองค์ประกอบที่มีค่ามากที่สุดถัดไป แต่มันซับซ้อนเกินไป
Neil Chowdhury

@nmichaels มีวิธีที่ดีที่สุดในการรับตำแหน่งสูงสุดทั้งหมดในรายการมากกว่าคำตอบที่ยอมรับหรือไม่?
Shaik moeed

18

คำตอบที่เลือก (และอื่น ๆ ส่วนใหญ่) ต้องผ่านอย่างน้อยสองรายการ
นี่คือโซลูชัน One Pass ซึ่งอาจเป็นตัวเลือกที่ดีกว่าสำหรับรายการที่ยาวขึ้น

แก้ไข:เพื่อแก้ไขข้อบกพร่องสองข้อที่ชี้ให้เห็นโดย @John Machin สำหรับ (2) ฉันพยายามเพิ่มประสิทธิภาพการทดสอบโดยพิจารณาจากความน่าจะเป็นแบบคาดการณ์ล่วงหน้าของแต่ละเงื่อนไขและการอนุมานที่ได้รับอนุญาตจากรุ่นก่อน มันเป็นเพียงเล็กน้อยหากินการหาค่าเริ่มต้นที่เหมาะสมสำหรับการmax_valและmax_indicesที่ทำงานสำหรับกรณีที่เป็นไปได้ทั้งหมดโดยเฉพาะอย่างยิ่งถ้าสูงสุดที่เกิดขึ้นเป็นค่าแรกในรายการ - แต่ผมเชื่อว่ามันตอนนี้ไม่

def maxelements(seq):
    ''' Return list of position(s) of largest element '''
    max_indices = []
    if seq:
        max_val = seq[0]
        for i,val in ((i,val) for i,val in enumerate(seq) if val >= max_val):
            if val == max_val:
                max_indices.append(i)
            else:
                max_val = val
                max_indices = [i]

    return max_indices

4
(1) การจัดการรายการว่างต้องการความสนใจ ควรกลับมา[]ตามที่โฆษณาไว้ ("รายการส่งคืน") if not seq: return []รหัสควรจะเป็นเพียงแค่ (2) รูปแบบการทดสอบในลูปเป็นแบบย่อยที่ดีที่สุด: โดยเฉลี่ยในรายการแบบสุ่มเงื่อนไขval < maxvalจะพบบ่อยที่สุด แต่รหัสข้างต้นใช้เวลาทดสอบ 2 ครั้งแทนที่จะเป็นหนึ่งครั้ง
John Machin

+1 ถึง @John Machin ความคิดเห็นที่ไม่สอดคล้องกับ docstring และไม่ให้ฉันไปกับการโพสต์รหัสย่อยที่ดีที่สุด ในความเป็นจริงเนื่องจากคำตอบได้รับการยอมรับแล้วฉันได้สูญเสียแรงจูงใจเล็กน้อยเพื่อดำเนินการกับคำตอบของฉันต่อไปเนื่องจากฉันคิดว่าแทบจะไม่มีใครที่จะดูต่อไป - และมันนานกว่าทุกคน
martineau

1
@martineau: คำตอบ "ยอมรับ" ไม่จำเป็นต้อง "ยอมรับ" ฉันมักจะอ่านคำตอบทั้งหมด รวมถึงการแก้ไขของคุณ ซึ่งการทดสอบ 3 รายการในกรณีที่หายากได้==แทนที่จะเป็น 2 - elifเงื่อนไขของคุณจะเป็นจริงเสมอ
John Machin

@ John Machin: ฉันได้รับแรงบันดาลใจและแก้ไขให้ดียิ่งขึ้นไปอีก ตอนนี้เป็นการทดสอบเพิ่มเติมขั้นต่ำรวมไปถึงการปรับแต่งอื่น ๆ ขอบคุณสำหรับความคิดเห็นและคำวิจารณ์ที่สร้างสรรค์ของคุณ ฉันจับ True elifตัวเองเสมอFWIW ;-)
martineau

@John Machin: อืมมผลการจับเวลาของคุณดูเหมือนจะขัดแย้งกับตัวเองดังนั้นฉันจะลบสิ่งที่ฉันพูดไว้ในคำตอบเกี่ยวกับการกำหนดเวลาเพื่อที่ฉันจะได้สามารถดูว่าเกิดอะไรขึ้นต่อไป ขอบคุณสำหรับหัวขึ้น. ที่จริงฉันคิดว่าการทดสอบเวลา "ของจริง" จะต้องใช้ค่ารายการแบบสุ่ม
martineau

10

ฉันมากับต่อไปและการทำงานที่คุณสามารถมองเห็นได้ด้วยmax, minและคนอื่น ๆ ฟังก์ชั่นในช่วงรายการเช่นนี้

ดังนั้นโปรดพิจารณารายการตัวอย่างถัดไปค้นหาตำแหน่งสูงสุดในรายการa:

>>> a = [3,2,1, 4,5]

ใช้เครื่องกำเนิดไฟฟ้า enumerateและทำการหล่อ

>>> list(enumerate(a))
[(0, 3), (1, 2), (2, 1), (3, 4), (4, 5)]

ณ จุดนี้เราสามารถดึงตำแหน่งสูงสุดด้วย

>>> max(enumerate(a), key=(lambda x: x[1]))
(4, 5)

ด้านบนบอกเราสูงสุดอยู่ในตำแหน่งที่ 4 และค่าของเขาคือ 5

ตามที่คุณเห็นในการkeyโต้แย้งคุณสามารถหาค่าสูงสุดเหนือวัตถุที่ทำซ้ำได้ใด ๆ โดยกำหนดแลมบ์ดาที่เหมาะสม

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

PD: ตามที่ @PaulOyster จดบันทึกไว้ในความคิดเห็น ด้วยและช่วยให้คำหลักใหม่ที่หลีกเลี่ยงข้อยกเว้นยกเมื่ออาร์กิวเมนต์เป็นรายการที่ว่างเปล่าPython 3.xminmaxdefaultValueErrormax(enumerate(list), key=(lambda x:x[1]), default = -1)


2
นี่เป็นทางออกที่ดีกว่าเนื่องจากเกี่ยวข้องกับการผ่านครั้งเดียว ความคิดเห็นเล็กน้อยแม้ว่า: 1. ไม่จำเป็นต้องแสดงรายการ () การแจงนับ 2. แลมบ์ดาจะดีกว่าวงเล็บ 3 นาที () และสูงสุด () ตอนนี้มีพารามิเตอร์เริ่มต้น (ซึ่งถูกส่งคืนจากอินพุตว่าง) ดังนั้นสามารถใช้ (ตัวอย่างเช่นค่าเริ่มต้น = -1) เพื่อหลีกเลี่ยงข้อยกเว้น ValueError และ 4 โปรดเปลี่ยนเป็น max () เนื่องจากนี่เป็นคำถามเดิม
พอลหอยนางรม

ประมาณ 3 รายการใช่มันใช้ได้กับ Python 3.x เท่านั้น ฉันจะพูดถึงว่า และแก้ไขทุกสิ่งทุกอย่าง ;)
jonaprieto

2
สิ่งนี้จะค้นหาตำแหน่งของหนึ่งในองค์ประกอบที่มีค่าสูงสุด (ครั้งแรก) เมื่อมันเกิดขึ้นมากกว่าหนึ่งครั้งในรายการ - ดังนั้นจึงไม่ตอบคำถามที่ถาม
martineau

8

ฉันไม่สามารถทำซ้ำประสิทธิภาพการทำงานของ @ SilentGhost- ที่ยกมาโดย @martineau นี่คือความพยายามของฉันกับการเปรียบเทียบ:

=== maxelements.py ===

a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50,
             35, 41, 49, 37, 19, 40, 41, 31]
b = range(10000)
c = range(10000 - 1, -1, -1)
d = b + c

def maxelements_s(seq): # @SilentGhost
    ''' Return list of position(s) of largest element '''
    m = max(seq)
    return [i for i, j in enumerate(seq) if j == m]

def maxelements_m(seq): # @martineau
    ''' Return list of position(s) of largest element '''
    max_indices = []
    if len(seq):
        max_val = seq[0]
        for i, val in ((i, val) for i, val in enumerate(seq) if val >= max_val):
            if val == max_val:
                max_indices.append(i)
            else:
                max_val = val
                max_indices = [i]
    return max_indices

def maxelements_j(seq): # @John Machin
    ''' Return list of position(s) of largest element '''
    if not seq: return []
    max_val = seq[0] if seq[0] >= seq[-1] else seq[-1]
    max_indices = []
    for i, val in enumerate(seq):
        if val < max_val: continue
        if val == max_val:
            max_indices.append(i)
        else:
            max_val = val
            max_indices = [i]
    return max_indices

ผลลัพธ์จากแล็ปท็อปรุ่นเก่าที่ใช้ Python 2.7 บน Windows XP SP3:

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_s(me.a)"
100000 loops, best of 3: 6.88 usec per loop

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_m(me.a)"
100000 loops, best of 3: 11.1 usec per loop

>\python27\python -mtimeit -s"import maxelements as me" "me.maxelements_j(me.a)"
100000 loops, best of 3: 8.51 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_s(a100)"
1000 loops, best of 3: 535 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_m(a100)"
1000 loops, best of 3: 558 usec per loop

>\python27\python -mtimeit -s"import maxelements as me;a100=me.a*100" "me.maxelements_j(a100)"
1000 loops, best of 3: 489 usec per loop

7
a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 
         55, 23, 31, 55, 21, 40, 18, 50,
         35, 41, 49, 37, 19, 40, 41, 31]

import pandas as pd

pd.Series(a).idxmax()

9

นั่นคือวิธีที่ฉันมักจะทำ


6

คุณยังสามารถใช้แพคเกจ numpy:

import numpy as np
A = np.array(a)
maximum_indices = np.where(A==max(a))

นี่จะส่งคืนอาร์เรย์ numpy ของดัชนีทั้งหมดที่มีค่าสูงสุด

หากคุณต้องการเปลี่ยนเป็นรายการ:

maximum_indices_list = maximum_indices.tolist()

5
>>> max(enumerate([1,2,3,32,1,5,7,9]),key=lambda x: x[1])
>>> (3, 32)

นี่เป็นสิ่งที่ผิด ลองใส่ตัวเลขสูงสุดไว้ตรงกลางของรายการ
goncalopp

1
นี่เป็นสิ่งที่ผิด คำถามบอกว่า "ค้นหาตำแหน่งทั้งหมดที่มีค่าสูงสุด"
Kapil

5

ด้วยวิธีแก้ปัญหาซึ่งให้การปรากฏครั้งแรกเท่านั้นสามารถทำได้โดยใช้numpy:

>>> import numpy as np
>>> a_np = np.array(a)
>>> np.argmax(a_np)
9

3

@shash ตอบคำถามนี้ที่อื่น

วิธี Pythonic เพื่อค้นหาดัชนีขององค์ประกอบรายการสูงสุดจะเป็น

position = max(enumerate(a), key=lambda x: x[1])[0]

ซึ่งไม่หนึ่งผ่าน แต่มันช้ากว่าโซลูชันโดย @Silent_Ghost และยิ่งไปกว่านั้น @nmichaels:

for i in s m j n; do echo $i;  python -mtimeit -s"import maxelements as me" "me.maxelements_${i}(me.a)"; done
s
100000 loops, best of 3: 3.13 usec per loop
m
100000 loops, best of 3: 4.99 usec per loop
j
100000 loops, best of 3: 3.71 usec per loop
n
1000000 loops, best of 3: 1.31 usec per loop

2

นี่คือค่าสูงสุดและดัชนีที่ปรากฏที่:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50, 35, 41, 49, 37, 19, 40, 41, 31]
>>> for i, x in enumerate(a):
...     d[x].append(i)
... 
>>> k = max(d.keys())
>>> print k, d[k]
55 [9, 12]

ต่อมา: เพื่อความพึงพอใจของ @SilentGhost

>>> from itertools import takewhile
>>> import heapq
>>> 
>>> def popper(heap):
...     while heap:
...         yield heapq.heappop(heap)
... 
>>> a = [32, 37, 28, 30, 37, 25, 27, 24, 35, 55, 23, 31, 55, 21, 40, 18, 50, 35, 41, 49, 37, 19, 40, 41, 31]
>>> h = [(-x, i) for i, x in enumerate(a)]
>>> heapq.heapify(h)
>>> 
>>> largest = heapq.heappop(h)
>>> indexes = [largest[1]] + [x[1] for x in takewhile(lambda large: large[0] == largest[0], popper(h))]
>>> print -largest[0], indexes
55 [9, 12]

คุณรู้ไหมว่ามันไร้ประสิทธิภาพแค่ไหน?
SilentGhost

1
หาเหตุผลเข้าข้างตนเอง: (1) "การเพิ่มประสิทธิภาพก่อนวัยอันควรคือ ... ฯลฯ " (2) มันอาจไม่สำคัญ (3) มันยังคงเป็นทางออกที่ดี บางทีฉันอาจจะเขียนมันใหม่เพื่อใช้งานheapq- การหาค่าสูงสุดจะมีเรื่องเล็กน้อย
hughdbrown

ในขณะที่ฉันชอบที่จะเห็นheapqวิธีการแก้ปัญหาของคุณฉันสงสัยว่ามันจะทำงาน
SilentGhost

2

แนวคิดที่คล้ายกันกับรายการความเข้าใจ แต่ไม่มีการแจกแจง

m = max(a)
[i for i in range(len(a)) if a[i] == m]

ฉันไม่ใช่ downvoter แต่โปรดทราบว่านี่ไม่ได้ดูดีจริงๆและจะทำงานได้ไม่ดี: การทำซ้ำผ่านดัชนีแทนที่จะผ่านรายการนั้นค่อนข้างน่าอึดอัดใจมากใน Python คุณพยายามหลีกเลี่ยงสิ่งนี้ เช่นกันมันช้ากว่าการแก้ปัญหาด้วยการแจกแจงเพราะการa[i]โทร
yo '

1

เพียงหนึ่งบรรทัด:

idx = max(range(len(a)), key = lambda i: a[i])

ดี แต่มันไม่ได้ส่งคืนดัชนีทั้งหมดเพียงแค่ดัชนีแรก
iggy

1

หากคุณต้องการรับดัชนีnจำนวนมากที่สุดในรายการที่เรียกว่าdataคุณสามารถใช้ Pandas sort_values:

pd.Series(data).sort_values(ascending=False).index[0:n]

0
import operator

def max_positions(iterable, key=None, reverse=False):
  if key is None:
    def key(x):
      return x
  if reverse:
    better = operator.lt
  else:
    better = operator.gt

  it = enumerate(iterable)
  for pos, item in it:
    break
  else:
    raise ValueError("max_positions: empty iterable")
    # note this is the same exception type raised by max([])
  cur_max = key(item)
  cur_pos = [pos]

  for pos, item in it:
    k = key(item)
    if better(k, cur_max):
      cur_max = k
      cur_pos = [pos]
    elif k == cur_max:
      cur_pos.append(pos)

  return cur_max, cur_pos

def min_positions(iterable, key=None, reverse=False):
  return max_positions(iterable, key, not reverse)

>>> L = range(10) * 2
>>> L
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> max_positions(L)
(9, [9, 19])
>>> min_positions(L)
(0, [0, 10])
>>> max_positions(L, key=lambda x: x // 2, reverse=True)
(0, [0, 1, 10, 11])

0

รหัสนี้ไม่ซับซ้อนเท่าคำตอบที่โพสต์ก่อนหน้านี้ แต่จะใช้งานได้:

m = max(a)
n = 0    # frequency of max (a)
for number in a :
    if number == m :
        n = n + 1
ilist = [None] * n  # a list containing index values of maximum number in list a.
ilistindex = 0
aindex = 0  # required index value.    
for number in a :
    if number == m :
        ilist[ilistindex] = aindex
        ilistindex = ilistindex + 1
    aindex = aindex + 1

print ilist

ilistในรหัสข้างต้นจะมีตำแหน่งทั้งหมดของจำนวนสูงสุดในรายการ


0

คุณสามารถทำได้หลายวิธี

วิธีการแบบเก่าคือ

maxIndexList = list() #this list will store indices of maximum values
maximumValue = max(a) #get maximum value of the list
length = len(a)       #calculate length of the array

for i in range(length): #loop through 0 to length-1 (because, 0 based indexing)
    if a[i]==maximumValue: #if any value of list a is equal to maximum value then store its index to maxIndexList
        maxIndexList.append(i)

print(maxIndexList) #finally print the list

อีกวิธีหนึ่งโดยไม่คำนวณความยาวของรายการและเก็บค่าสูงสุดให้กับตัวแปรใด ๆ

maxIndexList = list()
index = 0 #variable to store index
for i in a: #iterate through the list (actually iterating through the value of list, not index )
    if i==max(a): #max(a) returns a maximum value of list.
        maxIndexList.append(index) #store the index of maximum value
index = index+1 #increment the index

print(maxIndexList)

เราสามารถทำได้ใน Pythonic และวิธีที่ชาญฉลาด! ใช้ความเข้าใจในรายการเพียงบรรทัดเดียว

maxIndexList = [i for i,j in enumerate(a) if j==max(a)] #here,i=index and j = value of that index

รหัสของฉันทั้งหมดอยู่ใน Python 3

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