tl; д-р
вираз генератора , ймовірно , є найбільш продуктивним і простим рішенням вашої проблеми:
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 у Пітера Норвіга.