파이썬에서 list.index (might-not-exist)를 처리하는 가장 좋은 방법은 무엇입니까?


113

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

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

좋습니다. 간단하지만 아이디어를 얻을 수 있습니다. 이제 thing실제로 목록에 없을 수도 있습니다.이 경우 -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]

동일한 것을 달성하는 더 깨끗한 방법이 있습니까? 목록이 정렬되지 않았다고 가정 해 보겠습니다.


4
"... 어떤 경우에 -1을으로 전달하고 싶습니다 thing_index." -이것은 확실히 비파이 토닉입니다. 작업이 성공하지 못한 경우 (의미없는) 토큰 값을 전달하는 것은 눈살을 찌푸리게합니다. 예외는 실제로 올바른 방법입니다. 특히 thing_list[-1]는 목록의 마지막 항목을 의미하는 유효한 표현식 이기 때문 입니다.
Tim Pietzcker

@jellybean : 마른 세수는 P : ... 자바 코더 자리
Draemon

4
@Tim : str.find정확히하는 방법이 있습니다 : -1대상에서 바늘을 찾을 수 없을 때 반환합니다 .
SilentGhost

@Tim None이 더 좋을 것입니다 ... 그리고 이것은 dict [key] 대 dict.get [key]와 유사합니다
Draemon

@SilentGhost : 흠, 흥미 롭군요. 더 자세히 조사해야 할 수도 있습니다. str.index()검색 문자열이 없으면 예외가 발생합니다.
Tim Pietzcker

답변:


65

try-except 절을 사용하는 데 "더러운"것은 없습니다. 이것은 비단뱀적인 방법입니다. 그것은 당신이 거기에있는 유일한 코드이기 때문에 메서드에 의해서만 ValueError발생합니다 .index!

코멘트에 대답하기 :
파이썬을 쉽게 허가 취득하는 것보다 용서를 요구하지하는 철학은 잘 확립하고, 더는 index 다른 문제에 대한 이러한 유형의 오류를 제기하지 않습니다. 내가 생각할 수있는 것은 아닙니다.


29
예외는 예외적 인 경우에 해당되며 이는 거의 없습니다. 예외가 ValueError보다 더 구체적이라면 그런 문제는 없을 것입니다.
Draemon 2010-01-25

1
나는 그것이 그 방법 에서만 던져 질 수 있다는 것을 알고 있지만 그 이유 때문에 던져지는 것이 보장 됩니까? 인덱스가 실패하는 또 다른 이유를 생각할 수는 없지만, 당신이 생각할 수없는 것들에 대한 예외가 아닙니까?
Draemon 2010-01-25

4
{}.get(index, '')비단뱀 같지 않나요? 짧을수록 더 읽기 쉽습니다.
Esteban Küber

1
나는 확실하지 않다 때 키가 존재하고 dict.get (키) 할 것으로 예상 할 때 나는 DICT [키]를 사용하고, 내가 하고 뭔가 여기에 해당 찾고. None-1 대신 반환 하는 것이 좋지만 자신이 언급했듯이 str.find ()는 -1을 반환하므로 동일한 작업을 수행하는 list.find ()가 없어야하는 이유는 무엇입니까? 나는 "pythonic"인수를 사지 않는다
Draemon

3
그러나 요점은 가장 비단뱀적인 해결책은 -1 센티넬 값이 아닌 try / except 사용 하는 것입니다. IE를 다시 작성해야합니다 otherfunction. 반면에 고장이 나지 않았다면 ...
Andrew Jaffe

53
thing_index = thing_list.index(elem) if elem in thing_list else -1

한 줄. 단순한. 예외 없음.


35
간단합니다.하지만 두 번의 선형 검색을 수행하며 성능은 그 자체로 문제가되지 않지만 과도하게 보입니다.
Draemon 2010-01-25

4
@Draemon : 동의합니다-두 번의 패스를 할 것입니다.하지만 천 줄 코드 기반에서 이것이 병목 현상이 될 것 같지는 않습니다. :) 하나는 항상 명령형 솔루션을 선택할 수 있습니다 for.
Emil Ivanov

lambd와indexOf = lambda item,list_ : list_.index(item) if item in list_ else -1 # OR None
알라 Akiel

17

dict유형get기능 키가 사전에 존재하지 않는 경우에 제 2 인수 get는 반환해야하는 값입니다. 마찬가지로 키가 있으면 setdefault의 값을 반환하는 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 )

6

을 사용하는 코드에는 문제가 없습니다 ValueError. 예외를 피하고 싶다면 또 다른 한 줄짜리 설명이 있습니다.

thing_index = next((i for i, x in enumerate(thing_list) if x == thing), -1)

파이썬 2.6입니까? 나는 그것을 언급하지 않았지만 2.5를 사용하고 있습니다. 이것은 아마도 2.6에서 할 것입니다
Draemon

1
@Draemon : 예, next()함수는 Python 2.6 이상에 있습니다. 그러나 2.5 용으로 구현하는 것은 쉽습니다. Python 2.5 용 next () 함수 구현을
jfs

4

이 문제는 언어 철학 중 하나입니다. 예를 들어 Java에서는 예외가 흐름 제어 보다는 오류가 발생한 "예외 상황"에서만 실제로 사용되어야한다는 전통이 있습니다 . 처음에는 Java 예외가 느리기 때문에 성능상의 이유로 이었지만 이제는 이것이 허용되는 스타일이되었습니다.

대조적으로 파이썬은 ValueError여기에서 논의 하는 것과 같이 정상적인 프로그램 흐름을 나타 내기 위해 항상 예외를 사용 했습니다. 파이썬 스타일에서 이것에 대해 "더러운"것은 없으며 그 출처가 더 많이 있습니다. 더 일반적인 예는 더 이상 값이 없음을 알리기 위해 반복기의 메서드에 의해 StopIteration발생 하는 예외 입니다 next().


사실, JDK는 발생 방법 내가하지 않도록 철학은 실제로 자바에 적용된다 해요, 그래서 너무 많은 체크 된 예외. StopIteration예외가 의미하는 바가 명확하게 정의 되어 있기 때문에 그 자체로 문제가 없습니다 . ValueError너무 일반적입니다.
Draemon

나는 예외가 흐름 제어에 사용되어서는 안된다는 생각을 언급하고 있었다 : c2.com/cgi/wiki?DontUseExceptionsForFlowControl , 자바가 가지고있는 확인 된 예외의 수 만큼은 아니지만 , 완전히 다른 토론 : mindview.net/Etc/Discussions / CheckedExceptions
Tendayi Mawushe

4

이 작업을 자주 수행하는 경우 도우미 기능에서 제거하는 것이 좋습니다.

def index_of(val, in_list):
    try:
        return in_list.index(val)
    except ValueError:
        return -1 

4

이것에 대해 😃 :

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 

1

이것에 대해 :

otherfunction(thing_collection, thing)

함수 인터페이스의 목록 인덱스처럼 구현에 따라 달라지는 것을 노출하는 대신 컬렉션과 사물을 전달하고 다른 함수가 "멤버십 테스트"문제를 처리하도록합니다. otherfunction이 컬렉션 유형에 구애받지 않도록 작성되면 다음과 같이 시작할 수 있습니다.

if thing in thing_collection:
    ... proceed with operation on thing

thing_collection이 목록, 튜플, 집합 또는 dict이면 작동합니다.

이것은 아마도 다음보다 분명합니다.

if thing_index != MAGIC_VALUE_INDICATING_NOT_A_MEMBER:

이것은 이미 다른 기능에있는 코드입니다.


1

다음은 어떻습니까?

temp_inx = (L + [x]).index(x) 
inx = temp_inx if temp_inx < len(L) else -1

0

목록의 ".index ()"메서드와 동일한 문제가 있습니다. 예외가 발생한다는 사실에는 문제가 없지만 설명이 아닌 ValueError라는 사실에 강력히 동의하지 않습니다. 그래도 IndexError인지 이해할 수 있습니다.

파이썬에서 유효한 색인이기 때문에 "-1"을 반환하는 것도 문제가되는 이유를 알 수 있습니다. 그러나 현실적으로 는 ".index ()"메서드가 음수를 반환 할 것으로 기대 하지 않습니다 .

여기에 한 줄 (좋아요, 다소 긴 줄입니다 ...)이 있고, 목록을 정확히 한 번 살펴보고 항목이 없으면 "None"을 반환합니다. 원하는 경우 -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
>>>

-2

왜 더럽다고 생각해야하는지 모르겠네요 ... 예외 때문에? oneliner를 원한다면 다음과 같습니다.

thing_index = thing_list.index(elem) if thing_list.count(elem) else -1

그러나 나는 그것을 사용하지 말 것을 권할 것입니다. 저는 Ross Rogers 솔루션이 최고라고 생각합니다. 객체를 사용하여 원하는 동작을 캡슐화하고 가독성을 희생하여 언어를 한계까지 밀어 붙이려 고하지 마십시오.


1
예, 예외 때문입니다. 귀하의 코드는 두 가지 선형 검색을 수행하지 않습니까? 그 성능은 여기서 정말로 중요하지 않습니다. SuperDuperList 솔루션은 훌륭하지만이 특정 상황에서는 과잉처럼 보입니다. 나는 예외를 잡는 것으로 끝날 것이라고 생각하지만 (내 미학적으로) 더 깨끗한 방법이 있는지보고 싶었습니다.
Draemon 2010-01-25

@Draemon : 여러분이 가지고있는 코드를 find()함수에 캡슐화하면 모두 깨끗해질 것입니다.)
SilentGhost

1
내 대답에는 두 개의 반대표가있는 반면 Emil Ivanov는 의미 상 동일하지만 가장 많이 찬성표 중 하나라는 점이 궁금합니다. 아마도 이것은 "in"연산자 대신 count ()를 사용했기 때문에 내 것이 더 느리기 때문일 것입니다 ... 적어도 그랬 으면
좋겠다는

-2

나는 제안한다 :

if thing in thing_list:
  list_index = -1
else:
  list_index = thing_list.index(thing)

2
이 솔루션의 문제점은 "-1"이 목록에 유효한 색인 (마지막 색인, 끝에서 첫 번째 색인)이라는 것입니다. 이를 처리하는 더 좋은 방법은 조건의 첫 번째 분기에서 False를 반환하는 것입니다.
FanaticD
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.