Python에서 맵, 필터 및 축소를 사용하는 방법

이것은 내 Functional Programming 포스트 시리즈의 일부입니다.

사용법 시연 map , filter , reduce .

이 함수는 모두 Python에 내장되어 있습니다. 실제로 원래 포함되지 않았지만 Functional Programming(Lisp, 내 생각에)에 대한 배경 지식을 가진 기여자가 이를 놓쳐서 추가했습니다.

지도



명명된 함수를 사용합니다.

def square(value):
    return value**2


a = [1, 2, 3]
b = map(square, a)
list(b)
# [1, 4, 9]

list로 이해하려면 Consuming a generator 섹션으로 건너뛰어야 합니다.
lambda , 즉 익명 함수를 사용합니다. 이것은 일반적으로 x를 변수로 사용합니다.

a = [1, 2, 3]
b = map(lambda x: x**2, a)
list(b)
# [1, 4, 9]


다음 두 섹션에서는 lambda 스타일을 사용하겠습니다.

필터




a = [1, 2, 3]
b = filter(lambda x: x > 2, a)
list(b)
# [3]


맵과 필터 결합. 가장 안쪽 호출이 먼저 평가됩니다(이 경우에는 map 호출).

a = [1, 2, 3]
b = filter(lambda x: x > 1, map(lambda x: x**2, a))
b
# [4, 9]


줄이다


reduce 를 사용하여 str 가 아니라 int 또는 list 와 같은 단일 값으로 출력하고 결과를 누적하는 목록에서 계산을 수행합니다.

여기에 모든 값을 함께 추가합니다(sum가 존재하지 않는 척).

Python 3에서는 reduce 를 가져와야 합니다. 그러나 mapfilter는 가져올 필요가 없습니다.

from functools import reduce


a = [1, 2, 3]
b = reduce(lambda x, y: x+y, a, 0)
b
# 6

lambda에는 두 개의 변수가 있습니다. 이전 반복의 값에 x를 사용하고 현재 항목에 y를 사용합니다. 첫 번째 반복에서 0를 이전 값으로 사용합니다.

각 반복에서 일어나는 일을 분석:

# prev  current
0     + 1
# result: 1

# prev  current
1     + 2
# result: 3

# prev  current
2     + 3 
# result: 6


우리는 이미 파이썬에 sum 함수를 가지고 있으므로 위에서 한 것은 새로운 것이 아닙니다.

다음으로, 1*5*6*7를 시작 값으로 사용하여 목록의 모든 값, 즉 1를 곱합니다.

a = [5, 6, 7]
b = reduce(lambda x, y: x*y, a, 1)
b
# 210


발전기 소비



Python 3에서 mapfilter는 이제 생성기입니다. 이것은 메모리 관점에서 더 효율적이지만 생성기의 값을 사용하려면 list 또는 for 루프를 사용해야 합니다.

b = map(square, a)

# Show a reference to the object which has computed nothing.
b
# <map object at 0x1019aa310>

# Consume all of the values.
c = list(b)
c
# [1, 4, 9]

# The generator is now empty.
list(b)
# []

# Calculate it over.
b = map(square, a)

# Demonstration with a for loop instead of list(b).
for i in b:
    print(i)
# 1
# 4
# 9


범위 지정 및 안전


map , reduce 또는 filter 에 값을 전달할 때 주의해야 할 한 가지는 실제 값이 참조가 아니라 호출에 있다는 것입니다. 이것은 let 키워드를 사용하는 JavaScript의 클로저와 같습니다.

다음은 표준 흐름입니다.

a = [1, 2, 3]
b = map(lambda x: x + 1, a)
list(b)
# [2, 3, 4]


그러나 여기에서는 정의a와 소비b 사이에map를 변경합니다. 그러나 우리는 b 에 대해 동일한 결과를 얻습니다.

a = [1, 2, 3]
b = map(lambda x: x + 1, a)
a = [9, 10]
list(b)
# [2, 3, 4]


일어난 일은 a[9, 10] 를 가리키도록 재할당했다는 것입니다. 이전 값[1, 2, 3]은 할당된 변수 이름 없이 호출되지 않은b 호출 범위에 여전히 존재합니다.

이것은 함수형 프로그래밍 원칙에 좋습니다. 사용되지 않은b 호출에는 알고 있는 값이 전달되었다는 의미에서 상태가 있습니다. 그러나 호출되지 않은 b는 변경될 수 있는 a의 외부 값에 의존하지 않습니다.
b 맵 중간에 a 에서 값을 계산한 다음 a가 다른 곳을 가리키거나 값이 변경되거나 크기가 변경된 경우 얼마나 예측할 수 없는지 생각해 보십시오.

Python은 목록을 반복할 때 목록의 크기를 변경하는 것을 방지하지 않습니다... 이 for는 반복할 때마다 끝에 하나를 추가하므로 마지막 요소에 도달하지 않습니다.

a = [1, 2, 3]
for x in a:
    a.append(x+1)


몇 초 후에 명령을 취소해야 했고 목록의 크기가 부풀려진 것을 보았습니다.

a[:20]
# [1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7, 6, 7, 8, 7, 8]
# len(a)
14968136


다행히도 Python은 사전을 반복할 때 사전을 업데이트할 때 사용자를 보호합니다.

c = {'A': 1}
for k in c:
    c['B'] = k



Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration


연결



Python에 대한 더 많은 글에 관심이 있으십니까? 나에게 유용한 Python 자료를 수집하는 3개의 주요 장소가 있습니다.

  • Python topic on Learn to Code - 초보자에게 좋지만 리소스 목록은 모든 수준에 유용합니다.
  • Python Cheatsheets
  • Python Recipes

  • 내가 만들고 싶은 것을 보고 싶다면 여기 내 모든 것Python repos on GitHub이 있습니다.

    좋은 웹페이지 즐겨찾기