Pythonic способ найти максимальное значение и его индекс в списке?

151

Если мне нужно максимальное значение в списке, я могу просто написать max(List), но что, если мне также нужен индекс максимального значения?

Я могу написать что-то вроде этого:

maximum=0
for i,value in enumerate(List):
    if value>maximum:
        maximum=value
        index=i

Но это выглядит утомительно для меня.

И если я напишу:

List.index(max(List))

Затем он будет повторять список дважды.

Есть ли способ лучше?

Sunny88
источник
Что вы подразумеваете под "он пройдет список два раза"? List.index (max (List)) у меня работает.
MWZ
14
@mwc: он будет повторять список один раз, чтобы определить максимальное значение, а затем повторить его во второй раз, чтобы найти индекс этого значения.
10
Не будет ли проблем с list.index (), если есть дублированные максимальные значения?
Логан Ян
@LoganYang да, может быть два элемента с одинаковым значением.
Флориан
Если порядок не важен, вы можете сделать что-то вроде List.sort () [- 1]
Флориан

Ответы:

186

Есть много вариантов, например:

import operator
index, value = max(enumerate(my_list), key=operator.itemgetter(1))
Свен Марнах
источник
2
Ах, я видел это в других местах, но я думал, что он вернет только одно значение, а не кортеж.
Sunny88
1
@ Sunny88: keyфункция используется только для определения максимального элемента. Элементы не изменены.
Свен Марнач
6
@SvenMarnach Почему бы не key=lambda e: e[1]вместо этого и тем самым избежать импорта?
спасательный круг
8
@lifebalance Использование itemgetter()быстрее, и избегание импорта не является целью, которую стоит преследовать. В некоторых случаях может быть целесообразно избежать внешних зависимостей, но импорт из стандартной библиотеки не является проблемой.
Свен Марнах
324

Я думаю, что принятый ответ великолепен, но почему бы вам не сделать это явно? Я чувствую, что больше людей поймут ваш код, и это согласуется с PEP 8:

max_value = max(my_list)
max_index = my_list.index(max_value)

Этот метод также примерно в три раза быстрее принятого ответа:

import random
from datetime import datetime
import operator

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

if __name__ == "__main__":
    from timeit import Timer
    t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Explicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

    t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
          "import random; import operator;"
          "l = [random.random() for _ in xrange(100)]")
    print "Implicit: %.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

Результаты, как они работают на моем компьютере:

Explicit: 8.07 usec/pass
Implicit: 22.86 usec/pass

Другой набор:

Explicit: 6.80 usec/pass
Implicit: 19.01 usec/pass
Escualo
источник
3
Не ожидал, что это будет быстрее. Это быстрее, даже когда я заменяю l на «l = [random.random () для _ в xrange (10000000)] + [2]», что гарантирует, что последний элемент самый большой.
Sunny88
14
@ Sunny88: для простого списка чисел, простой подход быстрее. Если в этом случае вам нужна производительность, я бы посоветовал использовать numpy.argmax(), что на моей машине еще в 30 раз быстрее. Если список содержит более сложные объекты, чем простые числа, подход в моем ответе может стать быстрее. Еще одно преимущество этого подхода состоит в том, что он может использоваться для произвольных итераторов, а не только для списков.
Свен Марнач
@ Свен-Марнах Быстрее будет numpy, если мне сначала нужно будет преобразовать мой список в массив numpy? Будет ли это быстрее для простого примера [0,1,0]?
tommy.carstensen
1
@ Свен-Марнах, я только что проверил. numpy.argmax, безусловно, самый медленный метод, и он дает неправильный ответ, если массив содержит строки вместо чисел с плавающей точкой или целых чисел.
tommy.carstensen
9
Не будет ли проблем с list.index (), если есть дублированные максимальные значения?
Логан Ян
20

Этот ответ в 33 раза быстрее, чем @Escualo, при условии, что список очень большой, и при условии, что это уже np.array (). Мне пришлось уменьшить количество прогонов теста, потому что тест рассматривает 10000000 элементов, а не только 100.

import random
from datetime import datetime
import operator
import numpy as np

def explicit(l):
    max_val = max(l)
    max_idx = l.index(max_val)
    return max_idx, max_val

def implicit(l):
    max_idx, max_val = max(enumerate(l), key=operator.itemgetter(1))
    return max_idx, max_val

def npmax(l):
    max_idx = np.argmax(l)
    max_val = l[max_idx]
    return (max_idx, max_val)

if __name__ == "__main__":
    from timeit import Timer

t = Timer("npmax(l)", "from __main__ import explicit, implicit, npmax; "
      "import random; import operator; import numpy as np;"
      "l = np.array([random.random() for _ in xrange(10000000)])")
print "Npmax: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("explicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Explicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

t = Timer("implicit(l)", "from __main__ import explicit, implicit; "
      "import random; import operator;"
      "l = [random.random() for _ in xrange(10000000)]")
print "Implicit: %.2f msec/pass" % (1000  * t.timeit(number=10)/10 )

Результаты на моем компьютере:

Npmax: 8.78 msec/pass
Explicit: 290.01 msec/pass
Implicit: 790.27 msec/pass
portforwardpodcast
источник
Просто чтобы уточнить: ускорение просто из-за обалденной реализации C по сравнению с чистым python? Или есть способ улучшить ответ @ Escualo, используя чистый python?
максимум
Если вы хотите использовать Python 3.6, вы можете сделать что-то вроде: "l = np.array ([random.random () для _ в диапазоне (10000000)])") print (f "Npmax: {(1000 * t. timeit (число = 10) / 10): 5.2f} мсек / проход ")
Петр Сийда
Это было на 2,7
portforwardpodcast
1
Что ж, скорость numpy.argmaxвыглядит потрясающе, пока вы не дадите ему обработать стандартный список Python. Тогда скорость лежит между явной и неявной версией. я думаюnp.array что не просто создает список, но он сохраняет некоторую дополнительную информацию в нем - например, минимальные и максимальные значения (просто гипотеза).
Мирослав Опока
18

Со встроенной библиотекой Python это довольно просто:

a = [2, 9, -10, 5, 18, 9] 
max(xrange(len(a)), key = lambda x: a[x])

Это говорит, maxчтобы найти наибольшее число в списке [0, 1, 2, ..., len(a)], используя пользовательскую функцию lambda x: a[x], которая говорит, что 0на самом деле 2, 1есть на самом деле 9, и т. Д.

Сунил Капил
источник
В Python 3 нет xrange, если вы хотите написать код, который будет работать как для Python 2, так и для Python 3, вы должны использовать range ().
Чунде Хуан
10
max([(v,i) for i,v in enumerate(my_list)])
Луис Собрецуева
источник
Это лучше, потому что вы можете адаптировать его для использования с чем-то другим, кроме кортежа.
wieczorek1990
Как именно это работает? Можете ли вы сломать процесс?
clabe45
Привет @ clabe45, он преобразует my_list в список кортежей (v, i), где v - каждый элемент моего списка, а i - соответствующий индекс, затем он получает кортеж со значением maximun (и со связанным с ним индексом)
Луис Собрецуева
4
Спасибо, вы можете опубликовать это в ответе? И как maxузнать, просто учитывать первый элемент каждого tuple ( v) при вычислении максимального значения?
clabe45
1
@ clabe45 Может быть, этот ответ приходит слишком поздно, но для других (таких как я), которые сталкивались с этой веткой сейчас, здесь: stackoverflow.com/questions/18296755/… это объяснение. Не в этой строке: «По умолчанию max будет сравнивать элементы по первому индексу, если первый индекс будет таким же, тогда он будет сравнивать второй индекс». Итак, я попробовал с list: l = [1,1,1], а затем max ([(v, i) для i, v в enumerate (l)]), и это дает мне не первый 1, а последний один: (1,2) как результат. Я надеюсь, что это объясняет :)
Anupam Jain
10

Я бы предложил очень простой способ:

import numpy as np
l = [10, 22, 8, 8, 11]
print(np.argmax(l))
print(np.argmin(l))

Надеюсь, поможет.

Игорь Манжос
источник
4
max([(value,index) for index,value in enumerate(your_list)]) #if maximum value is present more than once in your list then this will return index of the last occurrence

Если максимальное значение присутствует более одного раза, и вы хотите получить все индексы,

max_value = max(your_list)
maxIndexList = [index for index,value in enumerate(your_list) if value==max(your_list)]
Таохидул Ислам
источник
1
Ага. Я почти опубликовал ответ, но потом я увидел, что у вас уже было то же решение с той же логикой в ​​одной строке для понимания списка.
WalyKu
2

Может быть, вам все равно нужен отсортированный список?

Попробуй это:

your_list = [13, 352, 2553, 0.5, 89, 0.4]
sorted_list = sorted(your_list)
index_of_higher_value = your_list.index(sorted_list[-1])
Маттиас
источник
1. Сортировка имеет более высокую временную сложность. 2. sorted_listимеет не индексы, а значения, поэтому он не будет работать.
1

извините за возрождение этой темы, но думал, что мой метод стоит добавить.

Имя списка в этом примере «список»

list.sort()
print(list[-1])

Это напечатает самое высокое значение в списке просто!

list.sort()сортирует список по значению элемента в таблице ASCII , поэтому эффективно сортирует список по возрастанию. Затем я просто печатаю последнее значение в списке (которое будет наибольшим числом), используя print(list[-1]).

Надеюсь это поможет!

Макки Джонстон
источник
5
мы не можем получить индекс таким образом
toing_toing
-1

Вот полное решение вашего вопроса с использованием встроенных функций Python:

# Create the List
numbers = input("Enter the elements of the list. Separate each value with a comma. Do not put a comma at the end.\n").split(",") 

# Convert the elements in the list (treated as strings) to integers
numberL = [int(element) for element in numbers] 

# Loop through the list with a for-loop

for elements in numberL:
    maxEle = max(numberL)
    indexMax = numberL.index(maxEle)

print(maxEle)
print(indexMax)
Самдом для мира
источник