lambda operator와 map, reduce, filter

lambda

lambda를 설명하기에 앞서 다음과 같은 함수가 있다고 해보자.

def increment(x):  
    return x + 1

increment(33) # 34  

이것을 lambda를 이용하면 단 한 줄로 나타낼 수 있다.

increment_lambda = lambda x: x+1

increment_lambda(33) # 34  

이렇게 하면 increment_lambda라는 함수는 아까 만든 increment함수와 완벽히 똑같은 함수가 된다.

lambda의 구조을 살펴보면

lambda [입력값] : [반환값]

이렇게 간단하지만 함수에서 있어야 할 것은 다 있다. 하지만 위의 예제만 보면 왜 굳이 lambda를 써야되는 지 잘 와닿지 않는다.

다음에 나오는 map, reduce, filter를 사용해보면 lambda가 언제 쓰이면 좋은지 바로 느낄 수 있을 것이다.


map

map( [함수], [배열])

map 함수는 배열에서 원소를 하나씩 꺼내어 함수를 적용시킨 결과를 다시 새로운 배열에 담아 반환해준다.(정확히 말해서는 map 클래스의 객체를 반환하는 것이고, list 함수를 적용했을 때 진정한 배열이 된다. 그래서 일반적으로 list 함수와 같이 사용된다.) 간단한 예제를 보자.

def square(x):  
    return x**2

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

각각의 원소를 제곱한 [1, 4, 9]라는 새로운 list가 출력될 것이다.

여기서 square 함수는 단지 map 함수의 argument로 넣기 위해서 위에 따로 만들었다. 이 때 아까 배운 lambda를 쓰면 위의 코드를 단 한 줄로 바꿀 수 있다.

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

위의 예제처럼 함수가 한 줄로 표현될 만큼 구성이 단순하고, 한 번만 사용하는 함수인 경우 lambda는 매우 유용하다. 그 말은 반대로 복잡하거나 자주 사용하게 되는 함수라면 lambda를 사용하지 않는 것이 더욱 효율적일 것이다.


reduce

reduce( [함수], [배열], [초기값])

reduce는 배열에서 두 원소의 함수 출력값이 뒤에 나오는 원소와 함께 또 다시 함수의 argument로 들어가며 이 과정이 순차적으로 반복되는 방식이다.

여기서 함수는 두 개의 parameter를 받는 함수여야하고 초기값은 생략될 수 있다. 초기값이 있으면 초기값과 배열의 첫 원소가 맨 처음 함수로 전달되고. 초기값이 없다면 배열의 첫 번째와 두 번째 원소가 맨 처음 함수로 전달된다.

말보다는 코드를 직접 보는 것이 이해가 빠를 것이다.

import functools  
def sum(x,y):  
    print((x,y))
    return x + y
functools.reduce(sum, [10, 20, 30, 40, 50]) # 150  

reduce 함수를 쓰기 위해서는 우선 functools라는 라이브러리를 import해야 한다. 위와 같이 sum 함수 중간에 print 함수를 넣어보면 reduce 함수의 연산과정을 한 눈에 확인할 수 있다.

아까와 마찬가지로 lambda를 이용하면 한 줄로 코드를 적을 수도 있다.

functools.reduce(lambda x,y: x+y, [10, 20, 30, 40, 50])  

이런 식으로 reduce 함수와 lambda를 이용하여 최댓값을 찾는 함수도 코드 한 줄로 구현할 수 있다.

functools.reduce(lambda x,y: x if x>y else y, [1, 9, 3, 5, 6, 4])  

filter

filter( [함수], [배열])

filter는 배열에 있는 각각의 원소들을 함수에 parameter로 넘겨주어 함수의 출력값이 True인 경우에만 그 원소를 새로운 배열에 담아 반환한다.

list(filter(lambda x: x>3, [1, 2, 3, 4, 5])) # [4, 5]  

4, 5만 3보다 크므로 [4, 5]로 출력된다.

이번엔 lambda, map, filter를 모두 활용하여 주어진 배열에서 자료형이 int인 원소만 뽑아낸 다음, 각각 제곱한 수들을 새로운 list로 만들어 낼 수도 있다.

complicated_list = [1, 2, "jupiny", {}, [], 4, 5]

list(map(lambda x: x**2, list(filter(lambda x: isinstance(x,int),complicated_list)))) # [1, 4, 16, 25]