programing

목록 이해 대 람다 + 필터

yoursource 2022. 12. 31. 20:40
반응형

목록 이해 대 람다 + 필터

아이템 속성별로 필터링하고 싶은 리스트가 있습니다.

다음 중 어느 것이 바람직한가(가독성, 퍼포먼스, 기타 이유)?

xs = [x for x in xs if x.attribute == value]
xs = filter(lambda x: x.attribute == value, xs)

사람마다 얼마나 아름다움이 다른지 이상하다.는, 보다 되어 .filter+lambda아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.

사용 수 .filter.

('에 의해 )입니다.Python 함수를 사용하는 즉시(에 의해 작성되었는지 여부에 관계없이)def ★★★★★★★★★★★★★★★★★」lambda 필터는 리스트의 이해보다 느릴 가능성이 있습니다.을 사용법또한 코드의 타이밍을 재어 병목현상을 발견하기 전까지는 퍼포먼스에 대해 크게 생각하지 않는 것이 좋습니다.하다, 하다, 하다, 하다.

적용 가능한 다른 오버헤드는 람다가 스코프 변수에 강제로 액세스해야 한다는 것입니다( ).value이는 로컬 변수에 액세스하는 것보다 느리고 Python 2.x에서는 목록 이해가 로컬 변수에만 액세스합니다.3.x 를 목록 3.x 에도 할 수 .value이 차이는 적용되지 않습니다.

고려해야 할 다른 옵션은 목록 이해 대신 생성기를 사용하는 것입니다.

def filterbyvalue(seq, value):
   for el in seq:
       if el.attribute==value: yield el

그런 다음 메인 코드(가독성이 매우 중요한 부분)에서 목록 이해와 필터를 모두 의미 있는 함수 이름으로 대체했습니다.

이것은 Python에서 다소 종교적인 문제입니다.Guido가 Python 3에서 삭제하는 것을 고려했지만, 결국엔 그것만으로 충분한 반발이 있었다.reduce빌트인에서 functools.block으로 이동했습니다.

개인적으로 목록 내용을 이해하는 것이 더 쉽다는 것을 알게 되었다. 일이 있는지 하게 알 수 있습니다.[i for i in list if i.attribute == value]모든 동작이 필터 기능 내부가 아닌 표면에 있기 때문이다.

두 접근법의 성능 차이는 미미하기 때문에 크게 걱정하지 않을 것입니다.이것이 당신의 어플리케이션에서 병목현상이 될 가능성이 거의 없는 것으로 판명되었을 경우에만 최적화할 것입니다.

또한 BDFL이 원했기 때문에filter 피토닉하게 멀어지고 있다

속도 차이는 거의 없기 때문에 필터를 사용할지 리스트를 작성할지는 취향에 따라 결정됩니다.다른 하는 것 ) comprehension을 하는 경향이 , comprehension을 가 한 가지 있습니다.filter

술어 P(x)의 대상이 되는 반복 가능한 X의 값을 추출하는 경우가 자주 있습니다.

[x for x in X if P(x)]

그러나 일부 함수를 먼저 값에 적용해야 할 경우가 있습니다.

[f(x) for x in X if P(f(x))]


예로서 「」를 참조해 주세요.

primes_cubed = [x*x*x for x in range(1000) if prime(x)]

쓰는 보다 조금 더 것 요.filter 지금

prime_cubes = [x*x*x for x in range(1000) if prime(x*x*x)]

, 「 」를 합니다.filter가격 대비 효과가 있습니다.큐브를 두 번 계산하는 문제(더 비싼 계산을 상상) 외에도 식을 두 번 쓰는 문제가 있어 드라이 미학을 위반합니다.이 경우, 저는 다음 명령을 사용할 수 있습니다.

prime_cubes = filter(prime, [x*x*x for x in range(1000)])

일일 ~일도 although although although although 。filter퍼포먼스가 절대적으로 중요하지 않은 경우(이 경우 Python을 사용하지 않는 경우)에는, 「빠른 방법」, 「Python 방식」은 그러한 것에 신경쓰지 않는 것입니다.

python 3에서는 filter()가 실제로는 반복 객체이기 때문에 필터링된 목록을 작성하려면 list()에 필터 메서드 호출을 전달해야 합니다.python 2에서는:

lst_a = range(25) #arbitrary list
lst_b = [num for num in lst_a if num % 2 == 0]
lst_c = filter(lambda num: num % 2 == 0, lst_a)

lists b와 c는 같은 값을 가지며 filter()가 등가 [z의 경우 x in y]였던 것과 거의 같은 시간에 완료되었습니다.단, 3에서는 이 같은 코드가 필터된 리스트가 아닌 필터 오브젝트를 포함하는 리스트c 를 남깁니다.3에서 동일한 값을 생성하는 방법:

lst_a = range(25) #arbitrary list
lst_b = [num for num in lst_a if num % 2 == 0]
lst_c = list(filter(lambda num: num %2 == 0, lst_a))

문제는 list()가 반복 가능한 것을 인수로 받아들이고 해당 인수로 새 목록을 만든다는 것입니다.그 결과 파이썬3에서 필터를 사용하면 원래 목록뿐만 아니라 filter()에서 출력을 반복해야 하기 때문에 [x for x in y if z] 메서드의 최대 2배의 시간이 소요됩니다.

은 목록 입니다.list가 A를 filter할 수 없습니다.list 콜(호출, ))len 「」의 만, 「」의 반환에서는 동작하지 않습니다.의 귀환과 함께 작동하지 않는다.filter를 참조해 주세요.

나 자신의 독학으로 비슷한 문제가 생겼다.

그 로 얻을 수 있는 , 그 방법이 있을 것이다.list filter에서와 약간 비슷합니다.lst.Where(i => i.something()).ToList()

편집: 이것은 2가 아닌 Python 3의 경우입니다(댓글 참조).

나는 두 번째 방법이 더 읽기 쉽다고 생각한다.이것은 정확히 어떤 의도인지 알려줍니다: 목록을 필터링합니다.
PS: '리스트'입니다.

filter내장 기능을 사용하면 속도가 약간 빨라집니다.

당신의 경우 리스트 이해가 조금 더 빠를 것으로 예상합니다.

필터는 그냥 그거에요.리스트의 요소를 필터링 합니다.정의에 기재되어 있는 것과 같은 것을 확인할 수 있습니다(앞에서 설명한 공식 문서 링크).반면 목록 이해는 이전 목록의 어떤 것에 대해 행동한 후 새로운 목록을 생성하는 것입니다.(필터와 리스트의 양쪽 모두에 의해 새로운 리스트가 작성되고 오래된 리스트 대신 조작이 실행되지 않습니다.여기 새로운 리스트는 완전히 새로운 데이터 타입을 가진 리스트와 같습니다.정수를 문자열로 변환하는 등)

이 예에서는 정의에 따라 목록 이해보다 필터를 사용하는 것이 좋습니다.단, 예를 들어 목록 요소에서 other_attribute를 가져오고 싶을 경우 목록 이해를 사용할 수 있습니다.

return [item.other_attribute for item in my_list if item.attribute==value]

이것이 내가 실제로 기억하는 필터와 목록 이해입니다.리스트내의 몇개의 항목을 삭제하고, 그 외의 요소는 그대로 해 둡니다.필터를 사용합니다.요소에서 직접 논리를 사용하여 특정 목적에 적합한 요약 목록을 작성합니다. 목록 이해를 사용하십시오.

여기 제가 목록 이해 후 필터링을 해야 할 때 사용하는 짧은 조각이 있습니다.필터, 람다, 리스트의 조합(고양이의 충성도, 개의 청결도라고도 불립니다).

이 경우 파일을 읽고 빈 줄, 코멘트 아웃한 줄 및 코멘트 뒤에 있는 줄을 삭제합니다.

# Throw out blank lines and comments
with open('file.txt', 'r') as lines:        
    # From the inside out:
    #    [s.partition('#')[0].strip() for s in lines]... Throws out comments
    #   filter(lambda x: x!= '', [s.part... Filters out blank lines
    #  y for y in filter... Converts filter object to list
    file_contents = [y for y in filter(lambda x: x != '', [s.partition('#')[0].strip() for s in lines])]

제가 이 일에 익숙해지는데 시간이 좀 걸렸어요.higher order functions filter 그래서 적응이 돼서 정말 좋아했어요.filter하고, 는 내가 것을 functional programming terms건 terms terms terms 。

그리고 다음 구절(Fluent Python Book)을 읽었습니다.

맵과 필터 함수는 여전히 Python 3에 내장되어 있지만 목록 압축과 제너레이터 압축이 도입되었기 때문에 그다지 중요하지 않습니다.listcomp 또는 genexp는 맵과 필터를 조합한 작업을 수행하지만 더 읽기 쉽습니다.

그리고 지금 생각해보면, 왜 굳이 그 개념에 신경 쓰느냐는 않을까?filtermap만약 당신이 이미 널리 퍼진 관용구들로 그것을 달성할 수 있다면, 리스트 컴프리션과 같은. ★★★★★★★★★★★★★★★★.maps ★★★★★★★★★★★★★★★★★」filters일종의 기능이죠.는 이, 음, 음, 음, 음, 음, 음, 음, 음, 음, in, in, in, in을 사용합니다.Anonymous functions스스

두 방법을 모두 map ★★★★★★★★★★★★★★★★★」listComp그리고 나는 그것에 대해 논쟁을 할 만한 적절한 속도 차이를 보지 못했다.

from timeit import Timer

timeMap = Timer(lambda: list(map(lambda x: x*x, range(10**7))))
print(timeMap.timeit(number=100))

timeListComp = Timer(lambda:[(lambda x: x*x) for x in range(10**7)])
print(timeListComp.timeit(number=100))

#Map:                 166.95695265199174
#List Comprehension   177.97208347299602

승인된 답변 외에 목록 이해 대신 필터를 사용해야 하는 코너 케이스가 있습니다.목록을 캐시할 수 없는 경우 목록 이해로 직접 처리할 수 없습니다.로는 ' 낫다'를 하는 경우가 .pyodbc데이터베이스에서 결과를 읽습니다.fetchAll()cursor이치노결과를 필터를.

cursor.execute("SELECT * FROM TABLE1;")
data_from_db = cursor.fetchall()
processed_data = filter(lambda s: 'abc' in s.field1 or s.StartTime >= start_date_time, data_from_db) 

여기서 목록 이해를 사용하면 다음과 같은 오류가 발생합니다.

TypeError: 캐시할 수 없는 유형: '리스트'

성능에 따라 다릅니다.

filter는 목록을 반환하는 것이 아니라 반복자를 반환하는 것입니다.목록의 '즉시' 필터링과 목록 변환이 필요한 경우 매우 큰 목록(1M 이상)에 대해 목록 이해 속도가 약 40% 느립니다.최대 10만 요소까지는 거의 차이가 없습니다.600,000 이후부터는 차이가 생기기 시작합니다.

않을 으로 변환됩니다.filter의의순순 순다다다다다

자세한 것은, https://blog.finxter.com/python-lists-filter-vs-list-comprehension-which-is-faster/ 를 참조해 주세요.

이상하게도 Python 3에서는 필터가 목록 압축보다 더 빠르게 수행됩니다.

저는 항상 목록 합성이 더 잘 될 거라고 생각했어요.예를 들어 [brand_names_db의 이름이 [없음]이 아닌 경우 이름]생성된 바이트 코드가 조금 더 나아요.

>>> def f1(seq):
...     return list(filter(None, seq))
>>> def f2(seq):
...     return [i for i in seq if i is not None]
>>> disassemble(f1.__code__)
2         0 LOAD_GLOBAL              0 (list)
          2 LOAD_GLOBAL              1 (filter)
          4 LOAD_CONST               0 (None)
          6 LOAD_FAST                0 (seq)
          8 CALL_FUNCTION            2
         10 CALL_FUNCTION            1
         12 RETURN_VALUE
>>> disassemble(f2.__code__)
2           0 LOAD_CONST               1 (<code object <listcomp> at 0x10cfcaa50, file "<stdin>", line 2>)
          2 LOAD_CONST               2 ('f2.<locals>.<listcomp>')
          4 MAKE_FUNCTION            0
          6 LOAD_FAST                0 (seq)
          8 GET_ITER
         10 CALL_FUNCTION            1
         12 RETURN_VALUE

그러나 실제로는 속도가 느립니다.

   >>> timeit(stmt="f1(range(1000))", setup="from __main__ import f1,f2")
   21.177661532000116
   >>> timeit(stmt="f2(range(1000))", setup="from __main__ import f1,f2")
   42.233950221000214

기타 답변 요약

답을 훑어보면, 우리는 목록 이해나 필터가 더 빠를 수도 있고, 심지어 그러한 문제에 관심을 갖는 것이 중요하거나 심지어 피조적인지 많은 앞뒤로 봐왔다.결국 답은 대부분 그렇듯이 상황에 따라 달라집니다.

되었습니다.in ""가 ""==는 매우 .filter+lambda계산 시간의 3분의 1(수분)을 식이 차지합니다.

나의 경우

제 경우 목록 이해 속도가 훨씬 빠릅니다(두 배).다만, 이것은 필터식이나 Python 인터프리터에 의해서 크게 다른 것이 아닐까 생각합니다.

직접 테스트해 보세요.

여기 간단한 코드 조각이 있습니다. 쉽게 적응할 수 있습니다.프로파일을 작성하면(대부분의 IDE는 간단하게 할 수 있습니다), 특정의 케이스에 대해서, 어느 쪽이 좋은지를 간단하게 결정할 수 있습니다.

whitelist = set(range(0, 100000000, 27))

input_list = list(range(0, 100000000))

proximal_list = list(filter(
        lambda x: x in whitelist,
        input_list
    ))

proximal_list2 = [x for x in input_list if x in whitelist]

print(len(proximal_list))
print(len(proximal_list2))

프로파일링을 쉽게 할 수 있는 IDE가 없는 경우 대신 이 IDE를 사용해 보십시오(내 코드베이스에서 추출되었기 때문에 조금 더 복잡합니다).이 코드 조각은 snakeviz를 사용하여 쉽게 시각화할 수 있는 프로파일을 만듭니다.

import cProfile
from time import time


class BlockProfile:
    def __init__(self, profile_path):
        self.profile_path = profile_path
        self.profiler = None
        self.start_time = None

    def __enter__(self):
        self.profiler = cProfile.Profile()
        self.start_time = time()
        self.profiler.enable()

    def __exit__(self, *args):
        self.profiler.disable()
        exec_time = int((time() - self.start_time) * 1000)
        self.profiler.dump_stats(self.profile_path)


whitelist = set(range(0, 100000000, 27))
input_list = list(range(0, 100000000))

with BlockProfile("/path/to/create/profile/in/profile.pstat"):
    proximal_list = list(filter(
            lambda x: x in whitelist,
            input_list
        ))

    proximal_list2 = [x for x in input_list if x in whitelist]

print(len(proximal_list))
print(len(proximal_list2))

당신의 질문은 매우 간단하지만 흥미롭습니다.프로그래밍 언어로서 파이썬이 얼마나 유연한지 보여줍니다.어떤 논리든 사용할 수 있고, 자신의 재능과 이해력에 따라 프로그램을 작성할 수 있습니다.정답만 맞으면 돼요.

둘 다할 수 인데, 저는 첫 필터링 방법인 '필터링', '필터링'을 합니다.my_list = [x for x in my_list if x.attribute == value]단순해 보이고 특별한 구문이 필요하지 않기 때문입니다.는 누구나 할 수 있습니다첫 이 더 ).

언급URL : https://stackoverflow.com/questions/3013449/list-comprehension-vs-lambda-filter

반응형