Como encontrar todas as posições do valor máximo em uma lista?

152

Eu tenho uma lista:

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]

o elemento max é 55 (dois elementos nas posições 9 e 12)

Preciso encontrar em quais posições o valor máximo está situado. Por favor ajude.

Prumo
fonte

Respostas:

210
>>> m = max(a)
>>> [i for i, j in enumerate(a) if j == m]
[9, 12]
SilentGhost
fonte
4
Boa resposta curta, se você não se importa de fazer várias passagens pela lista - o que é provável.
27510 martineau
Exceto que o 0 grande para isso é 2n, a lista é iterada por 2x, uma vez para determinar o máximo e outra vez para encontrar as posições do máximo. Um loop for que rastreia o máximo atual e sua posição pode ser mais eficiente para listas realmente longas.
Radtek
1
@radtek big O é apenas n. principais coeficientes são ignorados em grande O
michaelsnowden
1
Teoricamente, O (N) e O (2N) são os mesmos, mas, na prática, O (N) definitivamente terá um tempo de execução mais curto, especialmente quando N se aproxima do infinito.
Radtek 24/10/2015
314
a.index(max(a))

informará o índice da primeira instância do maior elemento valorizado da lista a.

nmichaels
fonte
8
Porém, isso só lhe dará a primeira instância e ele solicitou todos os índices em que o maior valor foi encontrado. Você precisaria fazer um loop nessa fatia usando para obter a lista restante em cada caso e manipular a exceção quando ela não for mais encontrada.
Jaydel #
10
Eu mencionei que isso daria apenas a primeira instância. Se você deseja todos eles, a solução do SilentGhost é muito mais bonita e menos propensa a erros.
Ncshaels
7
Pelo menos como eu vim para isso, a questão pede explicitamente para uma lista no caso de múltiplos maxima ...
emmagras
2
Tecnicamente, você pode usar isso para obter a primeira instância do maior elemento avaliado e, em seguida, configurá-lo para um número negativo ridiculamente grande e, em seguida, encontrar o próximo maior elemento avaliado, mas isso seria muito complexo.
Neil Chowdhury 14/10
@nmichaels Existe a melhor maneira de obter todas as posições de valor máximo em uma lista do que a resposta aceita?
Shaik moeed #
18

A resposta escolhida (e a maioria das outras) exige pelo menos duas passagens na lista.
Aqui está uma solução de uma passagem que pode ser uma escolha melhor para listas mais longas.

Editado: Para solucionar as duas deficiências apontadas por @John Machin. Pois (2) tentei otimizar os testes com base na probabilidade estimada de ocorrência estimada de cada condição e nas inferências permitidas dos predecessores. Foi um pouco complicado descobrir os valores apropriados de inicialização para max_vale max_indicesque funcionaram em todos os casos possíveis, especialmente se o valor máximo foi o primeiro valor da lista - mas acredito que sim.

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
Martineau
fonte
4
(1) O tratamento da lista vazia precisa de atenção. Deve retornar []como anunciado ("Lista de devolução"). O código deve ser simples if not seq: return []. (2) O esquema de teste em loop é subótimo: em média, em listas aleatórias, a condição val < maxvalserá a mais comum, mas o código acima realiza 2 testes em vez de um.
John Machin
+1 no comentário de @John Machin por capturar a inconsistência com a sequência de documentos e não me deixar escapar publicando código abaixo do ideal. Para ser sincero, como uma resposta já foi aceita, perdi um pouco de motivação para continuar trabalhando em minha resposta, pois supus que dificilmente alguém iria olhar para ela - e é muito mais longo do que todo mundo.
22810 martineau
1
@martineau: respostas "aceitas" não são necessariamente "aceitáveis". Eu geralmente leio todas as respostas. Incluindo sua revisão. O que faz 3 testes agora no caso raro em ==vez de 2 - sua elifcondição sempre será verdadeira.
quer
@ John Machin: Fiquei realmente inspirado e revi ainda mais. Agora diminuíram os testes adicionais mínimos, além de alguns outros ajustes. Obrigado por seus comentários e críticas construtivas. Eu peguei o sempre verdadeiro elifeu mesmo, FWIW. ;-)
martineau
@ John Machin: Hmmm, seus resultados de tempo parecem contradizer os meus, então removerei o que disse na minha resposta sobre o tempo para que eu possa analisar o que está acontecendo ainda mais. Obrigado pelo aviso. Na verdade, acho que um teste de tempo "real" precisaria usar valores de lista aleatórios.
martineau
10

Eu vim com o seguinte e funciona como você pode ver max, mine outras funções em listas como estas:

Portanto, considere o próximo exemplo de lista e descubra a posição do máximo na lista a:

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

Usando o gerador enumerate e fazendo uma fundição

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

Neste ponto, podemos extrair a posição de max com

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

O exposto acima nos diz que o máximo está na posição 4 e seu valor é 5.

Como você vê, no keyargumento, é possível encontrar o máximo sobre qualquer objeto iterável, definindo um lambda apropriado.

Espero que contribua.

PD: Como @PaulOyster observou em um comentário. Com Python 3.xo mine maxpermita uma nova palavra-chave defaultque evite a exceção de aumento ValueErrorquando o argumento estiver vazio.max(enumerate(list), key=(lambda x:x[1]), default = -1)

jonaprieto
fonte
2
Essa é uma solução melhor, pois envolve uma única passagem. Alguns comentários, no entanto: 1. não há necessidade de listar () a enumeração, 2. é melhor que o lambda entre parênteses, 3. min () e max () agora têm um parâmetro padrão (que é retornado na entrada vazia), portanto, pode usar (padrão = -1, por exemplo) para evitar uma exceção ValueError e 4. altere para max (), pois essa era a pergunta original.
Paul Oyster
cerca de 3 itens, sim, apenas funciona com o Python 3.x. Eu vou mencionar isso. E consertou tudo o resto. ;)
jonaprieto
2
Isso só encontraria a posição de um dos elementos com valor máximo (o primeiro) quando ocorrer mais de uma vez na lista - portanto, não responde à pergunta.
22618 martineau
8

Não consigo reproduzir o desempenho do @ SilentGhost-beat citado por @martineau. Aqui está o meu esforço com comparações:

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

Resultados de um laptop antigo e obsoleto executando o Python 2.7 no 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
John Machin
fonte
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

É assim que eu costumo fazer.

Arijit Laha
fonte
6

Você também pode usar o pacote numpy:

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

Isso retornará uma matriz numpy de todos os índices que contêm o valor máximo

se você quiser transformar isso em uma lista:

maximum_indices_list = maximum_indices.tolist()
user3569257
fonte
5
>>> max(enumerate([1,2,3,32,1,5,7,9]),key=lambda x: x[1])
>>> (3, 32)
Hari Roshan
fonte
Isto está errado. Tente colocar o número máximo no meio da lista.
goncalopp
1
Isto está errado. A pergunta diz "encontre todas as posições do valor máximo".
Kapil
5

Também é possível obter uma solução, que fornece apenas a primeira aparência , usando numpy:

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

@shash respondeu isso em outro lugar

Uma maneira Pythonic de encontrar o índice do elemento máximo da lista seria

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

Qual deles passa . No entanto, é mais lento que a solução do @Silent_Ghost e, ainda mais, do @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
serv-inc
fonte
2

Aqui está o valor máximo e os índices em que aparece:

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

Mais tarde: para a satisfação do @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]
hughdbrown
fonte
você percebe como isso é ineficiente?
SilentGhost 21/10
1
Racionalizações: (1) "A otimização prematura é a ... etc." (2) Provavelmente não importa. (3) Ainda é uma boa solução. Talvez eu o recodifique para usar heapq- encontrar o máximo seria trivial.
precisa saber é o seguinte
enquanto eu adoraria ver sua heapqsolução, duvido que funcionasse.
SilentGhost 21/10
2

Idéia semelhante com uma compreensão de lista, mas sem enumerar

m = max(a)
[i for i in range(len(a)) if a[i] == m]
Salvador Dalí
fonte
Eu não sou o defensor do voto negativo, mas observe que isso não parece muito bom e não terá um bom desempenho: iterar pelos índices em vez de pela lista é muito estranho no Python, você tenta evitar isso. Além disso, é certamente mais lento que a solução enumerate por causa da a[i]chamada.
yo '
1

Apenas uma linha:

idx = max(range(len(a)), key = lambda i: a[i])
divkakwani
fonte
Bom, mas ele não retorna TODOS os índices, apenas o primeiro.
iggy 16/01
1

Se você deseja obter os índices dos maiores nnúmeros em uma lista chamada data, pode usar o Pandas sort_values:

pd.Series(data).sort_values(ascending=False).index[0:n]
dannyg
fonte
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])

fonte
0

Este código não é tão sofisticado quanto as respostas postadas anteriormente, mas funcionará:

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 no código acima conteria todas as posições do número máximo na lista.

Sukrit Gupta
fonte
0

Você pode fazer isso de várias maneiras.

A velha maneira convencional é,

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

Outra maneira, sem calcular o comprimento da lista e armazenar o valor máximo para qualquer variável,

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)

Podemos fazê-lo de maneira pitônica e inteligente! Usando a compreensão da lista em apenas uma linha,

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

Todos os meus códigos estão em Python 3.

Taohidul Islam
fonte