ТЛ; др
A генератор выражений , пожалуй, самое эффективное и простое решение вашей проблемы:
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
result = next((i for i, v in enumerate(l) if v[0] == 53), None)
# 2
Объяснение
Есть несколько ответов, которые обеспечивают простое решение этого вопроса с помощью списочных представлений.
Хотя эти ответы совершенно правильны, они не являются оптимальными.
В зависимости от вашего варианта использования, могут быть значительные выгоды от внесения нескольких простых изменений.
Основная проблема, с которой я сталкиваюсь при использовании понимания списка для этого варианта использования, заключается в том, что будет обработан весь список , хотя вам нужно только найти элемент 1 .
Python предоставляет простую конструкцию, которая здесь идеальна. Это называется выражение генератора . Вот пример:
# Our input list, same as before
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
# Call next on our generator expression.
next((i for i, v in enumerate(l) if v[0] == 53), None)
Мы можем ожидать, что этот метод будет работать в основном так же, как и списки в нашем тривиальном примере, но что если мы работаем с большим набором данных?
Вот где преимущество использования метода генератора вступает в игру.
Вместо того, чтобы создавать новый список, мы будем использовать ваш существующий список в качестве нашего итерируемого и использовать next()
, чтобы получить первый элемент из нашего генератора.
Давайте посмотрим, как эти методы работают по-разному в некоторых больших наборах данных.
Это большие списки, состоящие из 10000000 + 1 элементов, с нашей целью в начале (лучший) или в конце (худший).
Мы можем проверить, что оба этих списка будут работать одинаково, используя следующее понимание списка:
Список понятий
"Худший случай"
worst_case = ([(False, 'F')] * 10000000) + [(True, 'T')]
print [i for i, v in enumerate(worst_case) if v[0] is True]
# [10000000]
# 2 function calls in 3.885 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 3.885 3.885 3.885 3.885 so_lc.py:1(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
"Лучший случай"
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print [i for i, v in enumerate(best_case) if v[0] is True]
# [0]
# 2 function calls in 3.864 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 3.864 3.864 3.864 3.864 so_lc.py:1(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Генератор выражений
Вот моя гипотеза для генераторов: мы увидим, что генераторы будут значительно лучше работать в лучшем случае, но аналогично в худшем.
Это увеличение производительности в основном связано с тем, что генератор вычисляется лениво, то есть он будет вычислять только то, что требуется для получения значения.
Худший случай
# 10000000
# 5 function calls in 1.733 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 2 1.455 0.727 1.455 0.727 so_lc.py:10(<genexpr>)
# 1 0.278 0.278 1.733 1.733 so_lc.py:9(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
# 1 0.000 0.000 1.455 1.455 {next}
Лучший кейс
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print next((i for i, v in enumerate(best_case) if v[0] == True), None)
# 0
# 5 function calls in 0.316 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 0.316 0.316 0.316 0.316 so_lc.py:6(<module>)
# 2 0.000 0.000 0.000 0.000 so_lc.py:7(<genexpr>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
# 1 0.000 0.000 0.000 0.000 {next}
ЧТО ?! В лучшем случае уничтожает понимания списка, но я не ожидал, что наш худший случай настолько превзойдет понимание списка.
Как так? Честно говоря, я мог только строить догадки без дальнейших исследований.
Возьмите все это с небольшим количеством соли, я не проводил здесь никакого надежного профилирования, просто какое-то очень простое тестирование. Этого должно быть достаточно, чтобы понять, что выражение генератора является более производительным для этого типа поиска по списку.
Обратите внимание, что это все основной встроенный python. Нам не нужно ничего импортировать или использовать какие-либо библиотеки.
Впервые я увидел эту технику для поиска в курсе Udacity cs212 с Питером Норвигом.