python에서 list.index(존재하지 않을 수 있음)를 처리하는 가장 좋은 방법?
다음과 같은 코드가 있습니다.
thing_index = thing_list.index(thing)
otherfunction(thing_list, thing_index)
그, 、 플플 、 만지지있있 。, 이제thing 수 이 경우 을 제제 - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - 。이렇게 해서 -1번입니다.thing_index 수 index()원소를 찾을 수 없을 때 돌아올 수 있습니다.은 ★★★★★★★★★★★★★★★★★★★★★★★★.ValueError.
난 할 수 있어:
try:
thing_index = thing_list.index(thing)
except ValueError:
thing_index = -1
otherfunction(thing_list, thing_index)
하지만 이건 더럽게 느껴지고, 게다가 나도 모르겠어ValueError으로 다음과 같은 것 같습니다.발전기 기능을 바탕으로 다음과 같은 솔루션을 생각해 냈는데, 조금 복잡한 것 같습니다.
thing_index = ( [(i for i in xrange(len(thing_list)) if thing_list[i]==thing)] or [-1] )[0]
같은 일을 할 수 있는 더 깨끗한 방법은 없을까?목록이 정렬되지 않았다고 가정해 봅시다.
clause.try-except를 게 .try-except는 이것은 비단뱀의 방법이다. ValueError..index메서드만 있어요. 왜냐하면 그게 당신이 가진 유일한 코드니까요!
★★★★★★★★★★★★★★★★★★★★★★★:
Python에서는 허가를 받는 것보다 용서를 구하는 것이 더 쉬운 것이 잘 확립되어 있고, 없다. index에서는 다른 문제에서는 이러한 유형의 에러는 발생하지 않습니다.츠미야
thing_index = thing_list.index(elem) if elem in thing_list else -1
한 줄.간단하죠.예외는 없습니다.
이 유형에는 키가 사전에 존재하지 않는 경우 두 번째 인수가 있습니다.get반환해야 할 값입니다.마찬가지로 의 값을 반환합니다.dict키가 존재하는 경우 기본 파라미터에 따라 값을 설정한 다음 기본 파라미터를 반환합니다.
★★★★★★★를 연장할 수 있습니다.list 가지려고 타이핑하다getindexdefault★★★★★★ 。
class SuperDuperList(list):
def getindexdefault(self, elem, default):
try:
thing_index = self.index(elem)
return thing_index
except ValueError:
return default
그 후 다음과 같이 사용할 수 있습니다.
mylist = SuperDuperList([0,1,2])
index = mylist.getindexdefault( 'asdf', -1 )
이 작업을 자주 수행하는 경우 도우미 기능에 보관하는 것이 좋습니다.
def index_of(val, in_list):
try:
return in_list.index(val)
except ValueError:
return -1
문제가 없습니다.ValueError하다
thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)
이건 어때?
li = [1,2,3,4,5] # create list
li = dict(zip(li,range(len(li)))) # convert List To Dict
print( li ) # {1: 0, 2: 1, 3: 2, 4: 3, 5: 4}
li.get(20) # None
li.get(1) # 0
이 문제는 언어 철학 중 하나입니다.예를 들어 Java에서는 예외는 흐름 제어가 아닌 오류가 발생했을 때인 "예외적인 상황"에서만 사용해야 한다는 전통이 항상 있습니다.처음에는 Java 예외가 느리다는 이유로 퍼포먼스를 고려했지만 지금은 일반적인 스타일이 되었습니다.
은 ""이 "Python"이 "Python"이 "Python"이 "Python"이 "Python"이 "Python"이 "Python"이 "Python"이"이 "Python"이 "Python"이"이 "Python"이 "Python"이 "Python"이 "Python 비단뱀ValueError여기서 논의하는 바와 같이Python 스타일에서는 더러움이 없고 더러움이 많이 있습니다.보다 일반적인 예는 반복자의 예외입니다.next()더 이상의 값이 없음을 나타내는 방법.
이건 어때?
otherfunction(thing_collection, thing)
기능 인터페이스의 리스트인덱스와 같이 구현에 의존하는 것을 공개하는 것이 아니라 컬렉션과 것을 전달하고 다른 기능에서 "멤버십 테스트" 문제를 처리하도록 합니다.다른 함수가 collection-type-agnostic으로 쓰여져 있는 경우, 다음과 같이 시작됩니다.
if thing in thing_collection:
... proceed with operation on thing
thing_collection이 list, tuple, set 또는 dict일 경우 동작합니다.
이것은 다음보다 더 명확할 수 있습니다.
if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:
이미 다른 기능에서 사용하고 있는 코드입니다.
제안:
if thing in thing_list:
list_index = -1
else:
list_index = thing_list.index(thing)
이렇게 하면 어떨까요?
temp_inx = (L + [x]).index(x)
inx = temp_inx if temp_inx < len(L) else -1
시간이 꽤 지났지만 stdlib의 핵심 부분이고 수십 가지 잠재적인 방법이 있기 때문에 여러 가지 제안의 벤치마크를 가지고 가장 빠른 numpy 방식을 포함하면 도움이 될 것 같습니다.
import random
from timeit import timeit
import numpy as np
l = [random.random() for i in range(10**4)]
l[10**4 - 100] = 5
# method 1
def fun1(l:list, x:int, e = -1) -> int:
return [[i for i,elem in enumerate(l) if elem == x] or [e]][0]
# method 2
def fun2(l:list, x:int, e = -1) -> int:
for i,elem in enumerate(l):
if elem == x:
return i
else:
return e
# method 3
def fun3(l:list, x:int, e = -1) -> int:
try:
idx = l.index(x)
except ValueError:
idx = e
return idx
# method 4
def fun4(l:list, x:int, e = -1) -> int:
return l.index(x) if x in l else e
l2 = np.array(l)
# method 5
def fun5(l:list or np.ndarray, x:int, e = -1) -> int:
res = np.where(np.equal(l, x))
if res[0].any():
return res[0][0]
else:
return e
if __name__ == "__main__":
print("Method 1:")
print(timeit(stmt = "fun1(l, 5)", number = 1000, globals = globals()))
print("")
print("Method 2:")
print(timeit(stmt = "fun2(l, 5)", number = 1000, globals = globals()))
print("")
print("Method 3:")
print(timeit(stmt = "fun3(l, 5)", number = 1000, globals = globals()))
print("")
print("Method 4:")
print(timeit(stmt = "fun4(l, 5)", number = 1000, globals = globals()))
print("")
print("Method 5, numpy given list:")
print(timeit(stmt = "fun5(l, 5)", number = 1000, globals = globals()))
print("")
print("Method 6, numpy given np.ndarray:")
print(timeit(stmt = "fun5(l2, 5)", number = 1000, globals = globals()))
print("")
메인 실행 시 기계에서 다음과 같은 인쇄물이 출력되어 각 기능의 1000번의 평가판을 완료하는 데 걸리는 시간(초)이 표시됩니다.
방법 1: 0.75021027990098
방법 2: 0.7291318440002215
방법 3: 0.24142152300009911
방법 4: 0.525347197995084
방법 5, 지정된 목록 수: 0.5045417560013448
메서드 6, numpy 지정 np.ndarray: 0.011147511999297421
물론 이 질문은 리스트에 대해 구체적으로 묻기 때문에 가장 좋은 해결책은 try-except 방식을 사용하는 것입니다.그러나 python 데이터 구조 대신 numpy 데이터 구조 및 연산자를 사용함으로써 제공되는 속도 향상(여기서는 try-except에 비해 최소 20배 이상)은 매우 중요합니다.퍼포먼스가 중요한 많은 데이터 배열에 무언가를 구축한다면 저자는 numpy를 사용하여 초고속 C를 이용해야 합니다.바인딩을 합니다.(CPython 통역, 기타 통역 실적은 다를 수 있음)
그런데 방법 5가 방법 6보다 훨씬 느린 이유는 우선 numpy가 주어진 목록을 자체 numpy 배열로 변환해야 하기 때문입니다. 따라서 목록을 지정해도 numpy가 가능한 속도를 충분히 활용하지 못할 뿐입니다.
단도직입적으로 말씀드리면, 이 답변은 매우 나쁘고, 시간이 너무 복잡합니다.
여기 간단한 방법이 있습니다.
와 함께dict().get('key', 'some_value'), 의 값'key'키가 사전에 없는 경우 반환됩니다.'some_value'반환됩니다.
목록과 인덱스를 사용하여 이러한 사전을 만들 수 있습니다.
mylist = ['cat' 'dog', 'bunny']
mapping = {value: index for index, value in enumerate(mylist)}
그리고나서,mapping.get('key', 0)인덱스가 발견되면 인덱스를 반환합니다.None.
mapping.get('penguin', 0) # returns 0
리스트의 ".index()" 메서드에서도 같은 문제가 발생하고 있습니다.예외가 발생한다는 점에는 문제가 없지만 설명되지 않은 Value Error라는 점에는 크게 동의하지 않습니다.하지만 IndexError가 발생했는지는 이해할 수 있습니다.
Python에서는 유효한 인덱스이기 때문에 "-1"을 반환하는 것도 문제가 되는 이유를 알 수 있습니다.그러나 현실적으로 .index() 메서드가 음수를 반환할 것이라고는 생각하지 않습니다.
여기에 하나의 라이너(OK, 꽤 긴 줄...)가 표시되며, 목록을 정확히 한 번 훑어보고 항목을 찾을 수 없으면 "없음"을 반환합니다.원하신다면 -1을 반환하도록 다시 쓰는 것은 간단한 일입니다.
indexOf = lambda list, thing: \
reduce(lambda acc, (idx, elem): \
idx if (acc is None) and elem == thing else acc, list, None)
사용방법:
>>> indexOf([1,2,3], 4)
>>>
>>> indexOf([1,2,3], 1)
0
>>>
구현 비교
Python 3.8에서의 간단한 비교
TL;DR maybeidx2누락이 많은 어레이(n<100)를 제외하고 일반적으로는 고속입니다.
def maybeidx1(l, v):
return l.index(v) if v in l else None
def maybeidx2(l, v):
try:
return l.index(v)
except ValueError:
return None
테스트 케이스:
a = [*range(100_000)]
# Case 1: index in list
maybeidx1(a, 50_000)
Out[20]: 50000
maybeidx2(a, 50_000)
Out[21]: 50000
# Case 2: index not in list
maybeidx1(a, 100_000) is None
Out[23]: True
maybeidx2(a, 100_000) is None
Out[24]: True
타이밍 케이스 1
%timeit maybeidx1(a, 50_000)
1.06 ms ± 15.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit maybeidx2(a, 50_000)
530 µs ± 8.47 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
타이밍 케이스 2
%timeit maybeidx1(a, 100_000)
1.07 ms ± 21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit maybeidx2(a, 100_000)
1.07 ms ± 16.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
결과
를 사용합니다.maybeidx2대규모 어레이에 대응합니다.이 동작은 다음 동작으로 인해 고속입니다.maybeidx1값을 찾기 위해 어레이를 두 번 스캔합니다. 이 시간은 여전히 O(n) 시간이지만 승수가 2로 일정하기 때문에 실제로는 더 느립니다.이는 목록에 값이 존재하는 경우에 적용됩니다.값이 없을 경우 이들 시간은 거의 동일합니다.둘 다 전체 어레이를 정확히 한 번 스캔한 후 반환해야 합니다.None <>try-except어레이 사이즈가 10인 경우에도 케이스 2가 발생하지 않는 한 무시할 수 있습니다.그 다음에try-except오버헤드가 눈에 띕니다.§:
a = [*range(10)]
%timeit maybeidx1(a, 10)
191 ns ± 2.61 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%timeit maybeidx2(a, 10)
566 ns ± 5.93 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
는 (내수 있게 된다.a100달러
Python 3.6 이후로는 다음과 같은 방법이 있습니다.index ★★★★★★★★★★★★★★★★★」rindex-1예외를 두는 대신.
왜 더럽다고 생각하시는지 모르겠네요예외 때문에?오넬리너를 원하신다면, 여기 있습니다.
thing_index = thing_list.index(elem) if thing_list.count(elem) else -1
하지만 사용하지 말 것을 권하고 싶습니다.로스 로저스 솔루션이 최선이라고 생각합니다.객체를 사용하여 당신의 의도적인 행동을 캡슐화하고, 가독성을 희생하여 언어를 한계까지 밀어붙이지 마십시오.
언급URL : https://stackoverflow.com/questions/2132718/best-way-to-handle-list-indexmight-not-exist-in-python
'programing' 카테고리의 다른 글
| Excel: 문자열의 마지막 문자/문자열 일치 (0) | 2023.04.10 |
|---|---|
| 모든 것을 무시합니다.DS_모든 폴더 및 하위 폴더에 파일 저장 (0) | 2023.04.10 |
| 'tail' 명령어와 동등한 명령어 (0) | 2023.04.10 |
| 대상 주체 이름이 잘못되었습니다.SSPI 컨텍스트를 생성할 수 없습니다. (0) | 2023.04.10 |
| 다른 포크의 병합되지 않은 업스트림 풀 요청을 포크에 적용하려면 어떻게 해야 합니까? (0) | 2023.04.10 |