Python: Найти индекс минимального элемента в списке чисел [дубликаты]

На этот вопрос уже есть ответ здесь:

Получение индекса возвращенного элемента max или min с использованием max () / min () в списке 21 ответ

Как я могу найти индекс минимального элемента в списке чисел Python? Если бы они были целыми числами, я бы просто сделал:

minIndex = myList.index(min(myList))

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

ValueError: 0.13417985135 is not in list

Теперь я знаю, что могу просто прокрутить список и сравнить каждый элемент, чтобы увидеть, является ли он < (мин. + 0,0000000000001) и> (мин. - 0,0000000000001), но это немного грязно. Есть ли более элегантный (желательно встроенный) способ поиска индекса наименьшего элемента в списке чисел?

 jason10 дек. 2016 г., 01:22
этот вопрос помечен как дубликат, но у него есть лучший ответ, чем тот, который связан на баннере сверху imo, ymmv.
 mgilson09 нояб. 2012 г., 02:46
Это должно работать с целыми числами и числами с плавающей точкой ... Можете ли вы показать нам конкретный пример с числами с плавающей точкой, где это не так?т работаешь?
 Eric Postpischil09 нояб. 2012 г., 14:56
Сравнение с плавающей точкой не сомнительно. Сравнение двух чисел с плавающей точкой на равенство возвращает true тогда и только тогда, когда числа равны, в любой реализации с плавающей точкой, которая не является ужасно нарушенной. Одна потенциальная проблема - NaNs в списке. В таком случае минимальный оператор может вернуть NaN, но сравнение равенства сообщит, что NaN не равен чему-либо (включая себя), и это может вызвать проблемы в процедуре возврата индекса минимального значения. Если в списке нет NaN, это наводит на мысль о другой проблеме, которая еще не решена ни в одном из ответов.
 irrelephant09 нояб. 2012 г., 02:54
В поплавке конечное число битов, поэтому сравнение выигралоэто не проблема.

Ответы на вопрос(4)

val, idx = min((val, idx) for (idx, val) in enumerate(my_list))

затемval будет минимальное значение иidx будет его индекс.

 mgilson09 нояб. 2012 г., 04:36
@abarnert - ям, используя py27, на OS-X 10.5.8 (следовательно, 32-битный). На python3,range Безразлично»т дать список ... Может быть, это может быть проблемой? (Хотя для меня это работает быстрее :) - 83.4
 David Wolever12 нояб. 2013 г., 18:47
@ fractal_7 вы можете сделать несколько трюков с:itertools.groupby_, minimums = next(groupby(sorted((val, idx) for (idx, val) in enumerate(my_list)), key=lambda x: x[0]), []), Но это неЭто почти так же красиво, так что в этот момент я мог бы написать функцию, которая делает это лучше.
 abarnert09 нояб. 2012 г., 04:31
@mgilson: Когда я запускаю точно такой же тест, я получаю 333us против 187us, или в 2 раза быстрее, чем в 3,5 раза медленнее… (Python 3.3 против 2.7? 64-битный против 32-битный? Кто знает?) Между тем,index решение работает для любой итерируемой тоже; вам просто нужно добавитьlist(myiter), Космический штраф может быть неприемлемым в некоторых случаях, но штраф времени, вероятно, выиграл.быть (так как тыты уже делаешь N ходит по списку).
 abarnert09 нояб. 2012 г., 04:53
@mgilson: Да, но вы все еще можете нарезатьrange, а такжеindex это, в 3.3 (и ни один не требует внутреннего созданияlist). Так чтомог быть проблемой, но я бы нене ожидаю, что это будет. Если бы мне пришлось угадывать, яя предполагаю, что что-то было сделано для улучшения производительности выражения генератора между 2.7 и 3.3, илиenumerateпроизводительность с итерациями ... но если бы я действительно заботился, яЯ буду делать некоторые исследования, а не гадать
 abarnert09 нояб. 2012 г., 02:55
+1. Это и более эффективно, и проще (если вы понимаете выражения генератора), чем сначала получить минимум, а затем найти его. Кроме того, он автоматически работает для значений, которые можно заказать с
 Christos K.12 нояб. 2013 г., 16:28
@ Дэвид Вулевер, что если в одном и том же списке есть два или более минимальных значения? как вы получаете остальные, как вы их печатаете?
 mgilson09 нояб. 2012 г., 04:57
@abarnert - Да, я был удивлен, что все эти различные операции работали надrange когда я попробовал это. Тот'аккуратно. Я'Я просто говорю, что мыповторное сравнение яблок и апельсинов. Но, FWIW, для меня, я получаю более экстремальные результаты, используя py32 - не в пользу генератора. Так что, если генераторы получили капитальный ремонт, это было между 3,2 и 3,3 :). В противном случае, это может быть наша другая ОСS или ... Мне действительно нравятся эти маленькие сравнения производительности Python ... может быть, это 'потому что python позволяет легко сравнивать разные вещи ...
 Christos K.12 нояб. 2013 г., 19:40
@ Дэвид Вулевер спасибо за ответ. я сделал это таким образомminval = min(mylist)       for idx, val in enumerate(mylist):           if val == minval:               print idx   но я'Я собираюсь попробовать это тоже по-своему.
 mgilson09 нояб. 2012 г., 03:03
@abarnert - Тщательно делайте громкие заявления об эффективности. Это проблема, зависящая от размера. Рассматривать:python -m timeit -s 'my_list = range(1000)[::-1]' 'my_list.index(min(my_list))' - 96,8 единиц за цикл (и тщательно продумано для наихудшего сценария).python -m timeit -s 'my_list = range(1000)' 'min((val, idx) for (idx, val) in enumerate(my_list))' - 345 usec за цикл - в 3,5 раза медленнее для списка размером 1000. Однако у него есть и другие преимущества - Он работает для любого итерируемого, например.
 abarnert09 нояб. 2012 г., 05:06
@mgilson: ям на OS X 10.8.2. Из того, что ямы видели, по крайней мере, на Mac, 3.x имеет много оптимизаций, которые помогают 64-битной, но не 32-битной. И действительно, когда я запускаю 3.3 в 32-битном режиме, решение генератора переходит с 187us на 255us. Но главный вопрос здесь в том, почему что-то, что требует 83us на вашем, предположительно более старом и более медленном Mac, стоит 333 на моей почти самой лучшей модели середины 2012 года…
Решение Вопроса

Чтобы эффективно сканировать список один раз, чтобы найти минимальное значение, а затем снова сканировать его, чтобы найти индекс, вы можете сделать оба сразу:

from operator import itemgetter
min(enumerate(a), key=itemgetter(1))[0] 
 Jon Clements17 февр. 2015 г., 20:19
@Borealis Почему это имеет значение? Если там'с одинаковыми минимальными значениями, то минимум по-прежнему является минимумом ...
 mgilson09 нояб. 2012 г., 03:15
Все еще не так быстро, как OP 'код для списка размером 1000 :)
 Jon Clements09 нояб. 2012 г., 03:00
@DavidWolever Yupmin а такжеmax (лайкsort а такжеsorted) взять функцию сравнения ключей - очень полезно - просто желаюset взял это например
 Borealis17 февр. 2015 г., 20:18
Как бы это обрабатывало дублирующиеся минимальные значения?
 David Wolever09 нояб. 2012 г., 02:57
Ах, аккуратно. Я не'не понимаю, чтоmin (и предположительноmax) принятьkey аргумент. +1!
 Jon Clements17 февр. 2015 г., 20:35
@Borealis почему? Эмулирует поведениеlist.index (это то, что пытается сделать ОП), который находит индекспервый минимальное значение ... Не могли бы вы описать, что, по вашему мнению, необходимо учитывать в этом ответе?
 Borealis17 февр. 2015 г., 20:33
Напримерmylist = [1,2,1], Использование вашего метода вернет(0,1) (т. е. первый индекс в списке), когда фактически есть два минимальных значения. В идеале решение должно учитывать это

Стоит отметить несколько моментов здесь для некоторой перспективы.

Все настройки сделаны на OS-X 10.5.8 с python2.7

Джон Клементответ:

python -m timeit -s 'my_list = range(1000)[::-1]; from operator import itemgetter' 'min(enumerate(my_list),key=itemgetter(1))'
1000 loops, best of 3: 239 usec per loop    

Дэвид Воловерответ:

python -m timeit -s 'my_list = range(1000)[::-1]' 'min((val, idx) for (idx, val) in enumerate(my_list))
1000 loops, best of 3: 345 usec per loop

OP»ответ:

python -m timeit -s 'my_list = range(1000)[::-1]' 'my_list.index(min(my_list))'
10000 loops, best of 3: 96.8 usec per loop

Обратите внимание, что ям целенаправленно положить наименьший элемент в списке, чтобы сделать.index так медленно, как это могло бы быть. Было бы интересно посмотреть, при каком N повторение, как только ответы станут конкурентоспособными, с ответом с повторением дважды, который мы имеем здесь.

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

 abarnert09 нояб. 2012 г., 04:33
+1 за последний абзац. Тем более, что ОП специально просили самый элегантный, а не самый быстрый способ. Это'Стоит также упомянуть, что, если ОП были правыfloatне равны себе (хотя я нене думаю, чтоэто актуальная проблема ...), первые два решения все еще будут работать.

Использование метода argmin для массивов numpy.

import numpy as np
np.argmin(myList)

Однако это не самый быстрый метод: он в 3 раза медленнее, чем OP 'ответ на мой компьютер. Это может быть самым кратким, хотя.

 horaceT16 июл. 2018 г., 19:49
Это должен быть официальный ответ.

Ваш ответ на вопрос