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


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
Хороший короткий ответ, если вы не против сделать несколько проходов по списку - что вполне вероятно.
Мартино

За исключением того, что большой 0 для этого равен 2n, список итерируется через 2x, один раз для определения максимума, а другой раз для определения позиций максимума. Цикл for, который отслеживает текущий максимум и его положение, может быть более эффективным для действительно длинных списков.
Радтек

1
@radtek big O это просто n. ведущие коэффициенты игнорируются в больших O
michaelsnowden

1
Теоретически O (N) и O (2N) одинаковы, но практически O (N) определенно будет иметь более короткое время работы, особенно когда N приближается к бесконечности.
Радтек

314
a.index(max(a))

скажет вам индекс первого экземпляра самого ценного элемента списка a.


8
Это даст вам только первый экземпляр, и он запросил все индексы, где найдено наибольшее значение. Вам придется зацикливаться на этом, используя slice для получения оставшегося списка в каждом случае и обработки исключения, когда оно больше не найдено.
Джейдел

10
Я упомянул, что это даст только первый экземпляр. Если вам нужны все из них, решение SilentGhost намного красивее и менее подвержено ошибкам.
nmichaels

7
По крайней мере, так как я пришел к этому, вопрос явно просит список в случае нескольких максимумов ...
emmagras

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

@nmichaels Есть ли лучший способ получить все позиции максимального значения в списке, чем принятый ответ?
Шайк Моид

18

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

Отредактировано: для устранения двух недостатков, указанных @John Machin. Для (2) я попытался оптимизировать тесты, основанные на предположительной вероятности возникновения каждого условия и выводов, допускаемых предшественниками. Было немного сложно выяснить правильные значения инициализации для max_valи max_indicesкоторые работали для всех возможных случаев, особенно если max оказалось первым значением в списке - но я верю, что теперь это так.

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условие всегда будет верным.
Джон Мачин

@ Джон Мачин: Я был действительно вдохновлен и пересмотрел это еще больше. Теперь это минимальные дополнительные тесты, а также несколько других настроек. Спасибо за ваши комментарии и конструктивную критику. Я поймал всегда True elifсебя, 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аргументе вы можете найти максимум для любого итерируемого объекта, определив подходящую лямбду.

Я надеюсь, что это способствует.

PD: Как отметил @PaulOyster в комментарии. С и позволить новое ключевое слово , что во избежание исключения рейза , когда аргумент пустой список.Python 3.xminmaxdefaultValueErrormax(enumerate(list), key=(lambda x:x[1]), default = -1)


2
Это лучшее решение, так как оно включает в себя один проход. Несколько комментариев, однако: 1. нет необходимости перечислять () перечисление, 2. лямбда лучше заключать в скобки, 3. min () и max () теперь имеют параметр по умолчанию (который возвращается при пустом вводе), поэтому можно использовать это (по умолчанию = -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 ответил на это в другом месте

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]

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

1

Всего одна строка:

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

Хорошо, но он не возвращает ВСЕ индексы, только первый.
Игги

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.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.