Как искать список кортежей в Python

Поэтому у меня есть список кортежей, например:

[(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] 

Я хочу этот список для кортежа, числовое значение которого равно чему-то.

Таким образом, если я выполняю search(53) он вернет значение индекса 2

Есть простой способ сделать это?

8 Solutions collect form web for “Как искать список кортежей в Python”

 [i for i, v in enumerate(L) if v[0] == 53] 

Вы можете использовать понимание списка :

 >>> a = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] >>> [x[0] for x in a] [1, 22, 53, 44] >>> [x[0] for x in a].index(53) 2 

ТЛ; др

Выражение генератора, вероятно, является наиболее эффективным и простым решением вашей проблемы:

 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} 

КАКИЕ?! Лучший случай сдувает понимание списков, но я не ожидал, что наш худший случай превзойдет переписку в такой степени. Как так? Честно говоря, я мог только спекулировать без дальнейших исследований. Возможно, я попрошу об этом Stack Overflow.

Возьмите все это с кусочком соли, я не провел никакого прочного профилирования здесь, просто некоторые очень простые тесты. Я хотел бы включить некоторое профилирование памяти, но эти методы убегают от меня. Однако то, что мы видим здесь, достаточно, чтобы увидеть, что выражение для генератора более эффективно для такого поиска списка типов.

Обратите внимание, что это все базовый, встроенный питон. Нам не нужно ничего импортировать или использовать специальные библиотеки.

И чтобы дать кредит, когда кредит должен быть, я впервые увидел эту технику в свободном курсе, Udacity cs212 с Питером Норвигом .

Ваши кортежи в основном представляют собой пары ключ-значение – питон-диктофон –so:

 l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l)[53] 

Edit – aha, вы говорите, что хотите значение индекса (53, «xuxa»). Если это действительно то, что вы хотите, вам придется перебирать исходный список или, возможно, сделать более сложный словарь:

 d = dict((n,i) for (i,n) in enumerate(e[0] for e in l)) idx = d[53] 

Хм … ну, простой способ, который приходит на ум, – это преобразовать его в диктофон

 d = dict(thelist) 

и доступ d[53] .

РЕДАКТИРОВАТЬ : Ой, неправильно разобрал свой вопрос в первый раз. Похоже, вы действительно хотите получить индекс, в котором хранится заданное число. В этом случае попробуйте

 dict((t[0], i) for i, t in enumerate(thelist)) 

вместо простой старой конверсии. Тогда d[53] будет равно 2.

Предполагая, что список может быть длинным, а числа могут повторяться, рассмотрите использование типа SortedList из модуля Python sortedcontainers . Тип SortedList автоматически поддерживает кортежи по порядку по номеру и позволяет быстро выполнять поиск.

Например:

 from sortedcontainers import SortedList sl = SortedList([(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]) # Get the index of 53: index = sl.bisect((53,)) # With the index, get the tuple: tup = sl[index] 

Это будет работать намного быстрее, чем предложение по пониманию списка, выполнив двоичный поиск. Предложение словаря будет выполняться быстрее, но не будет работать, если могут быть дублированные номера с разными строками.

Если есть повторяющиеся числа с разными строками, вам нужно сделать еще один шаг:

 end = sl.bisect((53 + 1,)) results = sl[index:end] 

Разбирая на 54, мы найдем конечный индекс для нашего среза. Это будет значительно быстрее по длинным спискам по сравнению с принятым ответом.

Еще один способ.

 zip(*a)[0].index(53) 

[k для k, v в l, если v == ' delicia ']

здесь l – список кортежей – [(1, «juca»), (22, «james»), (53, «xuxa»), (44, «delicia»)]

И вместо того, чтобы преобразовать его в dict, мы используем llist-понимание.

*Key* in Key,Value in list, where value = **delicia**

Python - лучший язык программирования в мире.