programing

python에서 list.index(존재하지 않을 수 있음)를 처리하는 가장 좋은 방법?

jooyons 2023. 4. 10. 21:36
반응형

python에서 list.index(존재하지 않을 수 있음)를 처리하는 가장 좋은 방법?

다음과 같은 코드가 있습니다.

thing_index = thing_list.index(thing)
otherfunction(thing_list, thing_index)

그, 、 플플 、 만지지있있 。, 이제thing 수 이 경우 을 제제 - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - 。이렇게 해서 -1번입니다.thing_indexindex()원소를 찾을 수 없을 때 돌아올 수 있습니다.은 ★★★★★★★★★★★★★★★★★★★★★★★★.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

반응형