Як знайти у списку всі позиції максимального значення?


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, один раз для визначення max, а інший раз для пошуку позицій max. Цикл для циклу, який відстежує поточний макс і його положення, може бути більш ефективним для дійсно довгих списків.
radtek

1
@radtek великий 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
Принаймні, коли я прийшов до цього питання, в цьому питанні прямо запитується список у випадку множинних максимумів ...
emmagras

2
Технічно ви можете використовувати це, щоб отримати перший екземпляр найбільшого цінного елемента, а потім встановити його на смішно велике від’ємне число, а потім знайти наступний найбільший цінний елемент, але це було б занадто складно.
Ніл Чауддурі

@nmichaels Чи є найкращий спосіб отримати всі позиції максимального значення у списку, ніж прийнята відповідь?
shaik moeed

18

Обрана відповідь (і більшість інших) потребують щонайменше двох переходів через список.
Ось однопропускне рішення, яке може бути кращим вибором для більш довгих списків.

Відредаговано: Для усунення двох недоліків, на які вказував @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 тести замість одного.
Джон Махін

+1 до коментаря @John Machin за те, що я виявив невідповідність документообігу та не дозволив мені піти з розміщення суб-оптимального коду. Правдиво кажучи, оскільки відповідь вже була прийнята, я втратив трохи мотивації продовжувати працювати над своєю відповіддю, оскільки я припускав, що навряд чи хтось далі навіть не погляне на це - і це набагато довше, ніж у всіх інших.
мартіно

1
@martineau: "прийняті" відповіді не обов'язково "прийнятні". Я взагалі читаю всі відповіді. У тому числі ваш перегляд. Що робить 3 тести зараз у рідкісному випадку ==замість 2 - ваш elifстан завжди буде вірним.
Джон Махін

@John Machin: Я надихнувся і переглянув це ще більше. Тепер це мінімальні додаткові тести, а також кілька інших налаштувань. Дякуємо за ваші коментарі та конструктивну критику. Я впіймав завжди elifсамого True , FWIW. ;-)
мартіно

@John Machin: Хм, твої результати часу, здається, суперечать моїм власним, тому я вилучу те, що я сказав у своїй відповіді про терміни, щоб я міг вивчити, що відбувається далі. Дякую за голову. Насправді я думаю, що для "справжнього" тестування на часові терміни потрібно було б використовувати значення випадкових списків.
мартіно

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аргументі ви можете знайти максимум над будь-яким ітерабельним об'єктом, визначивши лямбда відповідним.

Я сподіваюся, що це сприяє.

ПД: Як зазначив @PaulOyster у коментарі. За Python 3.xдопомогою minі maxдозвольте нове ключове слово, defaultяке уникає виключення підвищення, ValueErrorколи аргумент порожній список.max(enumerate(list), key=(lambda x:x[1]), default = -1)


2
Це краще рішення, оскільки воно передбачає єдиний прохід. Хоча кілька коментарів: 1. немає необхідності перераховувати () перерахування, 2. лямбда краще бути скобками, 3. хв () і макс () тепер мають параметр за замовчуванням (який повертається на порожньому введенні), тому можна використовувати це (наприклад, за замовчуванням = -1), щоб уникнути виключення ValueError, і 4. будь ласка, змініть на max (), оскільки це було початкове питання.
Пол Ойстер

близько 3 елемента, так, він просто працює з Python 3.x. Я це згадаю. І зафіксував усе інше. ;)
jonaprieto

2
Це знайде позицію одного з максимально оцінених елементів (першого), коли він зустрічається неодноразово у списку, тому не відповідає на задане запитання.
мартіно

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

Це поверне нумерований масив усіх індексів, що містять максимальне значення

якщо ви хочете перетворити це на список:

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
Це неправильно. Питання говорить "знайти всі позиції максимального значення".
Капіль

5

Також рішення, яке надає лише перший вигляд , можна досягти, використовуючи numpy:

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

3

@shash відповів на це деінде

Пітонічним способом знайти індекс елемента максимального списку було б

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]

Я не прихильник, але зауважте, що це виглядає не дуже добре і не буде добре: ітерація через індекси замість списку дуже незручна в Python, ви намагаєтесь цього уникнути. Крім того, це, звичайно, повільніше, ніж рішення з перерахуванням через a[i]дзвінок.
йо '

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)

Ми можемо це зробити пітонічно і розумно! Використовуючи розуміння списку лише в одному рядку,

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

Всі мої коди в Python 3.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.