[python] 파이썬에서 튜플 목록을 검색하는 방법

따라서 다음과 같은 튜플 목록이 있습니다.

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

숫자 값이 무언가와 같은 튜플에 대해이 목록을 원합니다.

그래서 내가 할 경우 search(53)인덱스 값을 반환합니다2

이 작업을 수행하는 쉬운 방법이 있습니까?



답변

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


답변

tl; dr

발전기 표현은 아마 당신의 문제에 대한 가장 성능이 좋은 간단한 솔루션입니다 :

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 개의 요소 만 찾고 싶지만 전체 목록 이 처리된다는 것 입니다.

파이썬은 여기서 이상적인 간단한 구조를 제공합니다. 생성기 표현식 이라고합니다 . 다음은 그 예입니다.

# 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}

뭐?! 최선의 경우 는 목록 이해력을 날려 버리지 만 최악의 경우가 목록 이해력을 능가 할 것으로 예상하지 못했습니다. 방법 것입니다? 솔직히, 나는 더 이상의 연구없이 만 추측 할 수있었습니다.

이 모든 것을 소금으로 가져 가십시오. 여기에서는 강력한 프로파일 링을 실행하지 않았으며 매우 기본적인 테스트 만 수행했습니다. 이것은 생성기 표현식이 이러한 유형의 목록 검색에 더 효과적이라는 것을 인식하기에 충분해야합니다.

이것은 모두 기본 내장 파이썬입니다. 우리는 아무것도 가져 오거나 라이브러리를 사용할 필요가 없습니다.

저는 Peter Norvig와 함께 Udacity cs212 코스 에서 검색하는이 기술을 처음 보았습니다 .


답변

목록 이해력을 사용할 수 있습니다 .

>>> 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


답변

튜플은 기본적으로 키-값 쌍 (파이썬)입니다 dict.

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

편집-아하, 당신은 (53, “xuxa”)의 인덱스 값을 원한다고 말합니다. 이것이 실제로 원하는 것이라면 원래 목록을 반복하거나 더 복잡한 사전을 만들어야합니다.

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


답변

음 … 음, 떠오르는 간단한 방법은 그것을 dict로 변환하는 것입니다.

d = dict(thelist)

및 액세스 d[53].

편집 : 죄송합니다, 처음으로 질문을 잘못 읽었습니다. 실제로 주어진 숫자가 저장된 색인을 얻고 싶은 것처럼 들립니다. 이 경우 시도하십시오

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

평범한 이전 dict변환 대신 . 그러면 d[53]2가됩니다.


답변

목록이 길고 숫자가 반복 될 수 있다고 가정하면 Python sortedcontainers 모듈 에서 SortedList 유형을 사용하는 것이 좋습니다. . 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)