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



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



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


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



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



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

1033   8  

8 ответов:

[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

tl; dr

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 курс с Питером Норвигом.

ваши кортежи в основном пары ключ-значение--питон dict--так:

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

Edit -- ага, вы говорите, что хотите значение индекса (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].

EDIT: ой, неправильно понял ваш вопрос в первый раз. Похоже, вы действительно хотите получить индекс, в котором хранится данное число. В таком случае, попробуйте

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

вместо обычного dict преобразования. Тогда d[53] будет 2.

предположим, что список может быть длинным, цифры могут повторяться, можно использовать SortedList тип Python sortedcontainers module. Тип 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")]

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

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

Comments

    Ничего не найдено.