(python) 람다(lambda), 함수형 fileter / map / reduce
아무래도, 파이썬에서는 filter, map, reduce 보단 list comprehension을 사용하는게 더 pythonic하다는 의견이 주류인 것 같다.
https://www.artima.com/weblogs/viewpost.jsp?thread=98196
[python] Comprehension, Generator / iterator VS iterable / itertools
lambda
1
lambda args : returns
람다식은 filter, map, eval
같은 larger expression에 끼워서(inline ) 사용하는 경우 가독성을 높여준다.
복잡한 상황에서는 명확한 def
를 사용하는 편이 가독성이 더 좋다.
그리고 이런 식으로 람다식을 변수에 할당해서 쓰는 것은 지양해야 한다. (PEP8 )
1
2
sum = lambda a, b: a+b # No
def sum(a, b): return a+b # Yes
람다식을 사용하면 filter를 사용할 때 만들어야 하는 조건 함수를 대체할 수 있다.
1
print(list(filter(lambda x: x > 0, [1, -3, 2, 0, -5, 6])))
자바 8에서의 람다식과 비슷하지만 함수형 인터페이스를 구현할 필요가 없다는 점이 편리하고 반복문을 사용할 수 없는 eval 등에 사용할 수 있다.
map / filter / reduce
filter와 map은 다음 세가지를 사용해 대체할 수 있다. 넘파이를 사용한다면 당연히 브로드캐스트를 사용하는게 좋으나 넘파이를 사용하지 않는다면 뭘 선택할지는 본인 마음인 듯. 단순 리스트 순회같은 경우 함수형을 사용하는 것이 가독성에 도움이 됨
- numpy 브로드캐스트
- list comprehension
- generator
filter(function, iterable)
iterable에서 항목을 하나씩 function에 넘겨 return값이 true인 경우만 추출한다. 필터를 사용하면 반복문을 사용해 순회하며 비교해야 하는 작업을 간단히 처리할 수 있다. 즉 function에는 조건역할을 하는 function 이 들어가야 한다. ( return expr
) * 이렇게 True/False
를 반환하는 함수를 predicate (술어)라고 한다.
리스트에서 양수만 추출해서 리스트로 만드는 작업을 필터로 처리한 예다.
1
2
3
4
5
def positive(x):
return x > 0
print(list(filter(positive, [1, -3, 2, 0, -5, 6])))
filter 함수는 filter object를 반환 하므로, 이를 list()로 묶어 list로 만들어야 사용할 수 있다.
map(function, iterable)
iterable에서 각각의 원소에 대해 function을 적용한 결과를 묶어서 리턴해준다.
filter와 비슷하다고 생각할 수 있겠지만, filter는 function에 넘겨 수행한 결과가 True인 iterable의 항목을 추출하는 것이기 때문에 결과값을 추출하는 map과는 완전히 다르다.
또한 function이 조건함수여야만 하는 것은 아니다.
1
2
print(list(map(lambda x: x\*2, [1, 2, 3, 4, -1, -2, -5, -10])))
=>[2, 4, 6, 8, -2, -4, -10, -20]
filter의 경우 x*2를 입력하면 x*2의 결과가 항상 참이기 때문에 원래 리스트를 반환한다. map을 filter처럼 사용하면 다음과 같이 True/False
가 반환된다.
1
2
print(list(map(lambda x: x>0, [1, 2, 3, 4, -1, -2, -5, -10])))
=>[True, True, True, True, False, False, False, False]
filter와 map을 조합해서 사용하기
1
2
>>> list(map(lambda x: x\*2, filter(lambda x: x>0, [1, 2, 3, 4, -1, -2, -3, -4])))
[2, 4, 6, 8]
reduce
reduce는 내장 함수가 아니다… import 해주어야 함.
1
2
from functools import reduce
reduce(집계 함수, 순회 가능한 데이터[, 초기값])
*** 보통 reduce를 사용해야 하는 경우라면 list comprehension이 더 깔끔한 경우가 많다.
flatMap (custom)
- 파이썬에서는 기본적으로 flatMap을 지원하지 않아서, 직접 정의해서 사용해야 함.
- flatten2 방법은 list comp. 사용해서 자체 문법만으로 해결할 수 있어 간결하다는 장점.
- flatten 방법은 iter 요소를 사용해서 지연 평가 가능하다는 장점 (테스트는 안해봤는데 아마 될 것 같다.)
1
2
3
4
5
6
7
8
9
10
11
from itertools import chain
def flatten(iterable):
return chain.from\_iterable(iterable)
def flatten2(iterable):
return [j for i in iterable for j in i]
def flatMap(func, iterable):
return flatten(map(func, iterable))
파이썬 map filter reduce의 단점은…ㅠ
1
2
3
4
5
6
## python
result\_list = list( \
map(..., \
filter(..., \
x\_list.items()
)))
1
2
3
4
## java
result\_list = x\_list
.filter(...)
.map(...)
자바나 다른 언어 같은 경우는 위에서부터 필터 걸리고 맵 걸리고… 이런 식으로 위에서부터 데이터 처리 흐름 대로 읽어나갈 수 있는데 파이썬은 밑에서부터 list가 있고 그 다음 필터를 할거고… 그 다음 맵을 하고… 그 다음 리스트로 만든다. 로 읽어야 함.
코드는 위에서 부터 읽는게 편하기 때문에… 이런게 참 불편하다. 그래서 그냥 파이썬에서는
1
2
3
t1 = filter(..., x\_list.items())
t2 = map(..., t1)
result\_list = list(t2)
차라리 이렇게 쓰는게 낫지 않을지…
https://github.com/EntilZha/PyFunctional#simple-example라이브러리를 쓰면 chaining이 가능하긴 하다.