Làm thế nào để tìm tất cả các vị trí của giá trị tối đa trong một danh sách?


152

Tôi có một danh sách:

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]

phần tử tối đa là 55 (hai phần tử ở vị trí 9 và 12)

Tôi cần tìm vị trí nào (s) giá trị tối đa được đặt. Xin vui lòng giúp đỡ.

Câu trả lời:


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

4
Câu trả lời ngắn gọn nếu bạn không ngại thực hiện nhiều lần đi qua danh sách - rất có thể.
martineau

Ngoại trừ số 0 lớn cho số này là 2n, danh sách được lặp qua 2 lần, một lần để xác định max và lần khác để tìm vị trí của max. Một vòng lặp for theo dõi mức tối đa hiện tại và vị trí của nó có thể hiệu quả hơn cho các danh sách thực sự dài.
radtek

1
@radtek lớn O chỉ là n. các hệ số hàng đầu được bỏ qua trong O
michaelsnowden

1
Về mặt lý thuyết O (N) và O (2N) là như nhau nhưng thực tế, O (N) chắc chắn sẽ có thời gian chạy ngắn hơn, đặc biệt là khi N tiến đến vô cùng.
radtek

314
a.index(max(a))

sẽ cho bạn biết chỉ mục của phiên bản đầu tiên của phần tử có giá trị lớn nhất của danh sách a.


8
Điều này sẽ chỉ giúp bạn có được ví dụ đầu tiên và anh ta đã yêu cầu tất cả các chỉ mục nơi tìm thấy giá trị lớn nhất. Bạn sẽ phải lặp lại bằng cách sử dụng lát cắt để có được danh sách còn lại trong mỗi trường hợp và xử lý ngoại lệ khi không tìm thấy nữa.
jaydel

10
Tôi đã đề cập rằng nó sẽ chỉ đưa ra ví dụ đầu tiên. Nếu bạn muốn tất cả chúng, giải pháp của SilentGhost đẹp hơn và ít bị lỗi hơn.
nmichaels

7
Ít nhất là khi tôi đến với nó, câu hỏi yêu cầu một danh sách rõ ràng trong trường hợp có nhiều cực đại ...
emmagras

2
Về mặt kỹ thuật, bạn có thể sử dụng điều này để lấy phiên bản đầu tiên của phần tử có giá trị lớn nhất và sau đó đặt nó thành một số âm lớn vô lý, sau đó tìm phần tử có giá trị lớn nhất tiếp theo, nhưng điều đó quá phức tạp.
Neil Chowdhury

@nmichaels Có cách nào tốt nhất để có được tất cả các vị trí có giá trị tối đa trong danh sách hơn câu trả lời được chấp nhận không?
shaik moeed

18

Câu trả lời được chọn (và hầu hết các câu trả lời khác) yêu cầu ít nhất hai lần đi qua danh sách.
Đây là một giải pháp vượt qua có thể là lựa chọn tốt hơn cho danh sách dài hơn.

Đã chỉnh sửa: Để giải quyết hai thiếu sót được chỉ ra bởi @John Machin. Đối với (2) tôi đã cố gắng tối ưu hóa các thử nghiệm dựa trên xác suất xuất hiện của từng điều kiện và suy luận được cho phép từ những người tiền nhiệm. Đó là một chút khó khăn để tìm ra các giá trị khởi tạo thích hợp max_valmax_indiceshoạt động cho tất cả các trường hợp có thể, đặc biệt là nếu max xảy ra là giá trị đầu tiên trong danh sách - nhưng tôi tin rằng bây giờ nó đã làm được.

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) Việc xử lý danh sách trống cần chú ý. Nên trả lại []như quảng cáo ("Danh sách trả lại"). Mã nên đơn giản if not seq: return []. (2) Sơ đồ kiểm tra trong vòng lặp là tối ưu phụ: trung bình trong các danh sách ngẫu nhiên, điều kiện val < maxvalsẽ là phổ biến nhất nhưng đoạn mã trên có 2 bài kiểm tra thay vì một.
John Machin

Nhận xét +1 cho @John Machin vì đã bắt gặp sự không nhất quán với chuỗi doc và không để tôi thoát khỏi việc đăng mã phụ tối ưu. Thành thật mà nói, vì một câu trả lời đã được chấp nhận, tôi đã mất một chút động lực để tiếp tục làm việc với câu trả lời của mình, vì tôi cho rằng hầu như không ai có thể nhìn vào nó nữa - và nó dài hơn nhiều so với mọi người khác.
martineau

1
@martineau: câu trả lời "được chấp nhận" không nhất thiết là "chấp nhận được". Tôi thường đọc tất cả các câu trả lời. Bao gồm cả sửa đổi của bạn. Mà 3 bài kiểm tra bây giờ trong trường hợp hiếm ==thay vì 2 - elifđiều kiện của bạn sẽ luôn đúng.
John Machin

@ John Machin: Tôi đã thực sự có cảm hứng và sửa đổi nó hơn nữa. Bây giờ, nó đã giảm các thử nghiệm bổ sung tối thiểu, cộng với một vài điều chỉnh khác. Cảm ơn ý kiến ​​của bạn và những lời chỉ trích mang tính xây dựng. Tôi bắt gặp luôn luôn elifbản thân mình, FWIW. ;-)
martineau

@ John Machin: Hmmm, kết quả thời gian của bạn dường như mâu thuẫn với chính tôi, vì vậy tôi sẽ xóa những gì tôi đã nói trong câu trả lời của mình về thời gian để tôi có thể xem xét những gì đang diễn ra. Cảm ơn cho những người đứng đầu lên. Trên thực tế tôi nghĩ rằng một bài kiểm tra thời gian "thực" sẽ cần sử dụng các giá trị danh sách ngẫu nhiên.
martineau

10

Tôi đã đưa ra những điều sau đây và nó hoạt động như bạn có thể thấy max, minvà các chức năng khác trên các danh sách như sau:

Vì vậy, hãy xem xét danh sách ví dụ tiếp theo tìm ra vị trí tối đa trong danh sách a:

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

Sử dụng máy phát điện enumerate và đúc

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

Tại thời điểm này, chúng ta có thể trích xuất vị trí tối đa với

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

Những điều trên cho chúng ta biết, tối đa là ở vị trí 4 và giá trị của anh ta là 5.

Như bạn thấy, trong keyđối số, bạn có thể tìm thấy tối đa trên bất kỳ đối tượng lặp lại nào bằng cách xác định lambda thích hợp.

Tôi hy vọng rằng nó đóng góp.

PD: Như @PaulOurr đã ghi chú trong một bình luận. Với Python 3.xsự minmaxcho phép một từ khóa mới defaultmà tránh được những ngoại lệ tăng ValueErrorkhi đối số là danh sách trống.max(enumerate(list), key=(lambda x:x[1]), default = -1)


2
Đây là một giải pháp tốt hơn, vì nó liên quan đến một lần vượt qua. Mặc dù vậy, một vài nhận xét: 1. không cần liệt kê () bảng liệt kê, 2. lambda tốt hơn nên được ngoặc đơn, 3. min () và max () hiện có một tham số mặc định (được trả về trên đầu vào trống), vì vậy có thể sử dụng ví dụ (mặc định = -1) để tránh ngoại lệ ValueError và 4. vui lòng thay đổi thành max (), vì đây là câu hỏi ban đầu.
Paul Oyster

khoảng 3 mục, vâng, nó chỉ hoạt động với Python 3.x. Tôi sẽ đề cập đến điều đó. Và sửa mọi thứ khác. ;)
jonaprieto

2
Điều này sẽ chỉ tìm thấy vị trí của một trong các yếu tố có giá trị tối đa (đầu tiên) khi nó xuất hiện nhiều hơn một lần trong danh sách nên không trả lời câu hỏi.
martineau

8

Tôi không thể tái tạo hiệu suất đập @ SilentGhost được trích dẫn bởi @martineau. Đây là nỗ lực của tôi với sự so sánh:

=== 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

Kết quả từ một máy tính xách tay cũ chạy Python 2.7 trên 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

Đó là cách tôi thường làm.


6

Bạn cũng có thể sử dụng gói numpy:

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

Điều này sẽ trả về một mảng numpy của tất cả các chỉ mục có chứa giá trị tối đa

nếu bạn muốn biến nó thành một danh sách:

maximum_indices_list = maximum_indices.tolist()

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

Cái này sai. Cố gắng đặt số lượng tối đa ở giữa danh sách.
goncalopp

1
Cái này sai. Câu hỏi cho biết "tìm tất cả các vị trí của giá trị tối đa".
Kapil

5

Ngoài ra, một giải pháp, chỉ cung cấp sự xuất hiện đầu tiên , có thể đạt được bằng cách sử dụng numpy:

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

3

@shash đã trả lời điều này ở nơi khác

Một cách Pythonic để tìm chỉ mục của phần tử danh sách tối đa sẽ là

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

Mà không ai vượt qua . Tuy nhiên, nó chậm hơn giải pháp của @Silent_Ghost và, thậm chí còn hơn thế, @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

Đây là giá trị tối đa và các chỉ mục xuất hiện tại:

>>> 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]

Sau này: vì sự hài lòng của @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]

Bạn có nhận ra điều này kém hiệu quả như thế nào không?
SilentGhost

1
Hợp lý hóa: (1) "Tối ưu hóa sớm là ... vv" (2) Nó có thể không quan trọng. (3) Nó vẫn là một giải pháp tốt. Có lẽ tôi sẽ mã hóa lại để sử dụng heapq- việc tìm kiếm tối đa sẽ là chuyện nhỏ.
hughdbrown

Trong khi tôi muốn xem heapqgiải pháp của bạn , tôi nghi ngờ nó sẽ hoạt động.
SilentGhost

2

Ý tưởng tương tự với một sự hiểu biết danh sách nhưng không có liệt kê

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

Tôi không phải là người đánh giá thấp, nhưng lưu ý rằng điều này trông không thực sự tốt và sẽ không hoạt động tốt: lặp qua các chỉ số thay vì qua danh sách là rất khó xử trong Python, bạn cố gắng tránh điều này. Đồng thời, nó chắc chắn chậm hơn so với giải pháp liệt kê vì a[i]cuộc gọi.
yo '

1

Chỉ một dòng:

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

Đẹp, nhưng nó không trả về TẤT CẢ các chỉ mục, chỉ là cái đầu tiên.
iggy

1

Nếu bạn muốn lấy các chỉ số của nsố lớn nhất trong danh sách được gọi data, bạn có thể sử dụng 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ã này không phức tạp như các câu trả lời được đăng trước đó nhưng nó sẽ hoạt động:

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 trong đoạn mã trên sẽ chứa tất cả các vị trí của số lượng tối đa trong danh sách.


0

Bạn có thể làm điều đó theo nhiều cách khác nhau.

Cách thông thường cũ là,

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

Một cách khác mà không tính toán độ dài của danh sách và lưu trữ giá trị tối đa cho bất kỳ biến nào,

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)

Chúng ta có thể làm điều đó theo cách Pythonic và thông minh! Sử dụng hiểu danh sách chỉ trong một dòng,

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

Tất cả các mã của tôi là trong Python 3.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.