따라서 다음과 같은 튜플 목록이 있습니다.
[(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
숫자 값이 무언가와 같은 튜플에 대해이 목록을 원합니다.
그래서 내가 할 경우 search(53)
인덱스 값을 반환합니다2
이 작업을 수행하는 쉬운 방법이 있습니까?
답변:
[i for i, v in enumerate(L) if v[0] == 53]
발전기 표현은 아마 당신의 문제에 대한 가장 성능이 좋은 간단한 솔루션입니다 :
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 코스 에서 검색하는이 기술을 처음 보았습니다 .
튜플은 기본적으로 키-값 쌍 (파이썬)입니다 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]
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l).get(53)
목록이 길고 숫자가 반복 될 수 있다고 가정하면 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에 대해 이등분하면 슬라이스의 끝 인덱스를 찾을 수 있습니다. 이것은 허용되는 답변에 비해 긴 목록에서 훨씬 더 빠릅니다.
[k for k, v in l if v == ' delicia ']
여기서 l은 튜플 목록입니다-[(1, "juca"), (22, "james"), (53, "xuxa"), (44, "delicia")]
그리고 그것을 dict로 변환하는 대신 llist 이해력을 사용하고 있습니다.
*Key* in Key,Value in list, where value = **delicia**