Многие из нас знают, что enumerate
используется в ситуации, когда вы используете цикл for
и вам нужно знать индекс. Однако он имеет свои минусы. Согласно моим тестам с модулем timeit
, использование enumerate
делает код 2х медленнее. Добавление этого набора кортежей делает его медленнее до 3x. Эти цифры могут быть достаточно быстрыми для любого программиста, но люди, имеющие дело с алгоритмами, знают, что каждый бит кода, который вы можете оптимизировать, имеет огромное преимущество. Теперь, на мой вопрос,Python for loop index, without enumerate
Примером такого использования будет необходимость поиска индексов нескольких элементов в list
. Скажите, что нам нужно найти два элемента. Первые два решения, которые происходят со мной, как так:
x, y = 0, 0
for ind, val in enumerate(lst):
if x and y:
break
if val == "a":
x = ind
elif val == "b":
y = ind
Решение выше перебирает список, присвоить значения, чем сломаться, если два найден.
x = lst.index("a")
y = lst.index("b")
Это другое решение, которое я не хотел использовать, потому что оно оказалось действительно наивным. Он повторяет один и тот же список дважды, чтобы найти два элемента. Первое решение, делает это в одной итерации. Таким образом, по сложности, хотя мы делаем дополнительные задания в первом решении, он должен быть быстрее второго в более крупных списках. Но мое предположение не выполнено.
Вот код, я проверил производительность:https://codeshare.io/XfvGA
Второе решение было 2x 10 раз быстрее, чем первый, меняется с положением этих двух элементов. Есть несколько возможностей, которые это произойдет.
- Существует оптимизация в методе
index()
, о котором я не знаю. - Назначения нижнего уровня, выполняемые в методе
index()
. Возможно использование кода на C++. - Условия и дополнительные задания в первом решении делают его медленнее, чем ожидалось.
Даже эти причины не дотягивает объяснить скорость итерации списка дважды над перебором его раз. Хотя языки имеют большое различие во времени при запуске кода, сам процесс итерации является независимым от языка программирования, если вам нужно проверить миллион элементов, вам все равно нужно проверить миллион элементов (может быть рассмотрено map()
не намного быстрее, чем использование цикл для изменения значений).
Так что, если вам нужно, чтобы вы рассмотрели дела, которые я представил, чтобы уточнить, что здесь задается, вопрос может быть составлен таким образом. Мы знаем, что цикл Python for
на самом деле является while
, работающим в фоновом режиме (возможно, в C?). Таким образом, это означает, что индекс хранится по мере его увеличения где-то в памяти. Если бы был доступ к нему, это устранило бы стоимость вызова и распаковки enumerate
. Мой вопрос:
Есть ли такой способ существует? Если нет, может быть сделано (почему, или почему нет)?
источники я использовал для получения дополнительной информации по этой теме:
Python objects time complexity
Я не вижу оснований предполагать, что код, который имеет одиночный цикл (но который выполняет в два раза больше работы за проход), должен быть быстрее, чем два последовательных цикла, каждый из которых делает меньше работы за проход. Кроме того, обратите внимание, что одноточечная версия только коротких замыканий после обоих элементов была найдена. Если вы тестировали случайный ввод данных, это могло бы объяснить некоторые различия. –
@JohnColeman Конечно, работа, выполняемая в петлях, решает производительность. Однако теоретически работа, выполняемая этими циклами, может быть одинаковой (возможно, не в Python, а как псевдокод) и единственной итерации быстрее. – Rockybilly
Ваше утверждение о наличии ** индекса **, хранящегося где-то в памяти для каждого цикла 'for', также неверно. Протокол итератора просто должен вернуть значение или вызвать исключение 'StopIteration', когда вызывается' next() ', он явно свободен от требования поддерживать индекс в списке. Вот почему существует 'enumerate', чтобы имитировать эту функцию при переходе по фиксированному списку, когда это необходимо. –