파이썬 : 목록에서 찾기


585

나는 이것을 가로 질러왔다 :

item = someSortOfSelection()
if item in myList:
    doMySpecialFunction(item)

그러나 때로는 목록에서 인식되지 않는 것처럼 (문자열 목록 인 경우) 모든 항목에서 작동하지 않습니다.

이것이 목록에서 항목을 찾는 가장 'pythonic'방식 if x in l:입니까?


3
항목이 내부 요소 중 하나와 같으면 완벽하게 작동합니다 myList.
Niklas B.

1
그것이 일을하는 좋은 방법 이었다는 것을 의미합니까? 내 몇 번의 시험에서 공백이 있었을 수도 있고 줄 바꿈이 진행되고있을 수도 있습니다. "목록에서 찾기"(일반적으로)를 구현하는 좋은 방법인지 확인하고 싶었습니다
Stephane Rolland

답변:


1173

첫 번째 질문에 관해서는 : 해당 코드는 완벽하게 작동 item하며 inside 요소 중 하나와 같으면 작동해야합니다 myList. 어쩌면 항목 중 하나와 정확히 일치 하지 않는 문자열을 찾으려고하거나 정확 하지 않은 부동 소수점 값을 사용하고있을 수 있습니다.

두 번째 질문에 관해서는 : 목록에서 물건을 "찾는"경우 실제로 여러 가지 방법이 있습니다.

내부에 무언가가 있는지 확인

이것은 당신이 묘사하는 유스 케이스입니다 : 무언가가 목록 안에 있는지 여부를 확인하십시오. 아시다시피 그 in연산자를 사용할 수 있습니다 .

3 in [1, 2, 3] # => True

컬렉션 필터링

즉, 특정 조건에 맞는 순서로 모든 요소를 ​​찾는 것입니다. 이를 위해 목록 이해 또는 생성기 표현식을 사용할 수 있습니다.

matches = [x for x in lst if fulfills_some_condition(x)]
matches = (x for x in lst if x > 6)

후자는 생성기 를 반환합니다. 생성기 를 반복하는 즉시 빌드되는 게으른 목록의 일종으로 상상할 수 있습니다. 그건 그렇고, 첫 번째 것은 정확히

matches = filter(fulfills_some_condition, lst)

파이썬 2에서. 여기 당신은 직장에서 고차 함수를 볼 수 있습니다. Python 3에서는 filter목록이 아니라 생성기 같은 객체를 반환합니다.

첫 번째 사건 찾기

조건과 일치하는 첫 번째 항목 만 원하지만 (아직 무엇을 모르는 경우) for 루프를 사용하는 것이 좋습니다 ( else실제로 잘 알려지지 않은 절 사용 ). 당신은 또한 사용할 수 있습니다

next(x for x in lst if ...)

첫 번째 경기를 반환하거나 StopIteration아무것도 발견되지 않으면를 발생시킵니다. 또는 사용할 수 있습니다

next((x for x in lst if ...), [default value])

아이템의 위치 찾기

목록에는 특정 요소가 목록에서 어디에index 있는지 알고 싶을 때 유용한 방법이 있습니다 .

[1,2,3].index(2) # => 1
[1,2,3].index(4) # => ValueError

그러나 중복이 있으면 .index항상 가장 낮은 인덱스를 반환합니다 .......

[1,2,3,2].index(2) # => 1

중복이 있고 모든 색인을 원하면 enumerate()대신 사용할 수 있습니다 .

[i for i,x in enumerate([1,2,3,2]) if x==2] # => [1, 3]

10
스테판 : 내가 그것을 바꿔 보자는 : if x in list이다 없는 사람들이 내장 된 기능이 없다는 불평하는 것. 그들은 특정 조건과 일치하는 목록에서 무언가를 처음 발견하는 명확한 방법이 없다는 사실에 대해 불평합니다. 그러나 내 대답에서 언급했듯이 next()그것을 사용할 수 있습니다.
Niklas B.

3
@Stephane : 두 번째는 튜플을 생성하지 않지만 생성기는 기본적으로 아직 생성되지 않은 목록입니다. 결과를 한 번만 사용하려면 일반적으로 생성기가 선호됩니다. 그러나 생성 된 컬렉션을 나중에 여러 번 사용하려면 먼저 명시적인 목록을 만드는 것이 좋습니다. 내 업데이트를 살펴보면 이제 좀 더 구조화되었습니다 :)
Niklas B.

26
"처음 찾기"예제는 황금입니다. [list comprehension...][0]접근 방식 보다 더 pythonic 느낌
acjay

4
나는 파이썬 '기능적'기능에 점점 더 불만을 품고 있습니다. haskell에는 Data.List 모듈에 정확히 기능을하는 find 함수가 있습니다. 그러나 파이썬에서는 그렇지 않으며 라이브러리를 만들기 위해 작기 때문에 동일한 논리를 반복해서 다시 구현해야합니다. 무엇 낭비 ...
user1685095

3
에 kwarg이 있다면 그것은 좋은 것이다 index()라는 key등의 일을하는 것이 key인정 max(); 예를 들면 다음과 같습니다 index(list, key=is_prime)..
Curt

189

당신은 하나 개의 요소 또는 찾으려는 경우 None에 사용되는 기본을 next, 그것을 제기하지 않습니다 StopIteration항목이 목록에없는 경우 :

first_or_default = next((x for x in lst if ...), None)

1
next반복자를 첫 번째 매개 변수로 사용하고 목록 / 튜플은 반복자가 아닙니다. 그래서해야 first_or_default = next(iter([x for x in lst if ...]), None)docs.python.org/3/library/functions.html#next
Devy

7
@Devy : 맞아,하지만 (x for x in lst if ...)목록을 통해 생성기입니다 lst( 이다 반복자를). 그렇게 하면 훨씬 더 비싼 작업이 될 next(iter([x for x in lst if ...]), None)목록을 구성해야합니다 [x for x in lst if ...].
Erlend Graff

1
찾기 기능을 정의하기위한 추상화가 있습니다. if람다 의 부울 식을 캡슐화하면 find(fn,list)생성기 코드를 난독 처리하는 대신 일반적으로 작성할 수 있습니다 .
semiomant

22

Niklas B.의 답변은 매우 포괄적이지만 목록에서 항목을 찾으려면 색인을 얻는 것이 때로는 유용합니다.

next((i for i, x in enumerate(lst) if [condition on x]), [default value])

11

첫 번째 사건 찾기

그것에 대한 요리법이 있습니다 itertools:

def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    # first_true([a,b,c], x) --> a or b or c or x
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
    return next(filter(pred, iterable), default)

예를 들어 다음 코드는 목록에서 첫 번째 홀수를 찾습니다.

>>> first_true([2,3,4,5], None, lambda x: x%2==1)
3  

6

다른 대안 : 항목이 목록에 있는지 확인할 수 if item in list:있지만 주문은 O (n)입니다. 큰 항목 목록을 처리하고 있고 무언가가 목록의 구성원인지 여부 만 알아야하는 경우 목록을 먼저 세트로 변환하고 일정한 시간 설정 조회를 활용할 수 있습니다 .

my_set = set(my_list)
if item in my_set:  # much faster on average than using a list
    # do something

모든 경우에 올바른 해결책은 아니지만 경우에 따라 더 나은 성능을 제공 할 수 있습니다.

로 세트를 만드는 set(my_list)것도 O (n)이므로,이 작업을 한 번만 수행하면이 방법으로 더 빨리 수행 할 수 없습니다. 그래도 멤버쉽을 반복해서 확인해야하는 경우 초기 세트 생성 후 모든 조회에 대해 O (1)이됩니다.


4

문자열 목록으로 작업하는 동안 가능한 두 가지 검색 중 하나를 사용할 수 있습니다.

  1. list 요소가 항목 과 같은 경우 ( 'example'은 [ 'one', 'example', 'two']에 있음) :

    if item in your_list: some_function_on_true()

    [ 'one', 'ex', 'two']의 'ex'= = True

    [ 'one', 'ex', 'two']의 'ex_1'= = 거짓

  2. 목록 요소가 항목 과 같은 경우 ( 'ex'는 [ 'one,'example ','two ']에 있거나'example_1 '은 ['one ','example ','two ']에 있음) :

    matches = [el for el in your_list if item in el]

    또는

    matches = [el for el in your_list if el in item]

    그런 다음 len(matches)필요한 경우 확인 하거나 읽으십시오.


3

정의와 사용법

count()메소드는 지정된 값을 가진 요소 수를 리턴합니다.

통사론

list.count(value)

예:

fruits = ['apple', 'banana', 'cherry']

x = fruits.count("cherry")

질문의 예 :

item = someSortOfSelection()

if myList.count(item) >= 1 :

    doMySpecialFunction(item)

2
매우 긴 목록에서 효율적입니까? 백만의 목록을 말합니까?
3kstc 23.43에

1
확실하지 않습니다 !!!
josef

1

list.index(x)목록에서 x의 색인을 반환하거나 #ValueErrorx를 찾을 수없는 경우 메시지를 반환하는 x 를 사용 하는 대신 list에서 x list.count(x)의 발생 횟수를 반환하거나 (x가 실제로 목록에 있는지 확인) 또는 그렇지 않으면 (x가없는 경우) 0을 반환합니다. 멋진 점은 count()코드를 손상시키지 않거나 x를 찾을 수없는 경우 예외를 던지도록 요구한다는 것입니다.


나쁜 점은 요소를 세는 것입니다 . 요소가 발견 될 때 멈추지 않습니다. 그래서 성능은 큰 목록에 나쁘다
장 - 프랑수아 파브르

1

수집품에 값이 한 번 있는지 확인하려는 경우 'in'연산자를 사용하는 것이 좋습니다. 그러나 두 번 이상 검사하려는 경우 bisect 모듈을 사용하는 것이 좋습니다. bisect 모듈 데이터를 사용하여 정렬해야합니다. 따라서 데이터를 한 번 정렬하면 bisect를 사용할 수 있습니다. 내 기계에서 bisect 모듈을 사용하는 것이 'in'연산자를 사용하는 것보다 약 12 ​​배 빠릅니다.

다음은 Python 3.8 이상의 구문을 사용하는 코드의 예입니다.

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value
    )

data = list(range(1000))
# value to search
true_value = 666
false_value = 66666

# times to test
ttt = 1000

print(f"{bisect_search(data, true_value)=} {bisect_search(data, false_value)=}")

t1 = timeit(lambda: true_value in data, number=ttt)
t2 = timeit(lambda: bisect_search(data, true_value), number=ttt)

print("Performance:", f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

산출:

bisect_search(data, true_value)=True bisect_search(data, false_value)=False
Performance: t1=0.0220, t2=0.0019, diffs t1/t2=11.71

0

문자열 목록의 항목에 추가 / 원치 않는 공백이 없는지 확인하십시오. 항목을 찾을 수 없다는 설명을 방해 할 수있는 이유입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.