Byeonguk Kim

안녕하세요. 29살의 조금은 늦은 나이로 새롭게 개발자로 시작하는 신입 개발자입니다. 포트폴리오 [https://deaguowl.github.io]

파이썬 10. filter, map, reduce

14 Mar 2019 » Python

2019.03.14 TIL

(TIL은 스스로 이해한 것을 바탕으로 정리한 것으로 오류가 있을 수 있습니다)

# 질문에 답하기

  1. filter, map, reduce에 대해 이야기 해보기

filter

기본 문법

filter(f, iterable) 
  • filter는 여러개의 값들이 있을 때 특정한 기준에 대해 블리언을 적용하여 뽑아내는 것이다.

ex)

li = [-3, 5, 1, 2, -5, -4, 14] # 이 리스트 중에서 음수를 제거하고 싶다라고 하면
f = filter(lambda a: a>0, li) # filter을 활용하여 간단하게 끝낼 수 있다. but 하나씩 꺼낼 수 있다
  • 여기서 lazy evaluation이 나와야 한다.

lazy evaluation

lazy evaluation은 내가 원할 때 마다 결과값을 가지고 오는 것이다.
즉 함수의 실행시기를 내가 결정하게 된다.
이것이 filter, map, reduce, generator의 큰 특징이다.

filter, map, reduce는 모두 generator의 일종이다.

다시 돌아와서 위에

f = filter(lambda a: a>0, li) # next(f)라는 것으로 f에 해당하는 요소를 하나씩 뽑아낸다.

# 이것을 다 뽑아 보기 위해서는

for e in f:
    print(e) 
    
# 이것을 리스트로 만들기 위해서는

li = []

for e in f:
    li.append(e) 

# 혹은 한번에 적어줄 수도 있다.

result = []

for elem in li:
    if elem>0:
        result.append(elem)
        
# 같이 한번에 적어줄 수도 있게 되었다.
# 또 한줄로 적어줄 수도 있다. 

# 홀수 리스트로 한번에 뽑아내기

li2 = list(filter(lambda x: x%2, li)) # 한번에 리스트로 뽑아낸다.

# 짝수 리스트 한번에 뽑아내기

li2 = list(filter(lambda x:x%2==0, li))
  • filter는 특정한 f(x)에 대해 bloolean값을 필터하여 뽑아낸다.
  • 내가 다른 작업을 하다가 next(f)를 통해 하나를 뽑아내고 또 이후에 next(f)를 함으로서 그 다음 값들을 뽑아 올 수 있다. 메모리를 따로 쓰지 않는다는 장점이 있다.
  • 내가 함수의 실행시간을 결정할 수 있다는 것과, 메모리를 따로 저장하지 않고 바로 가지고 올 수 있다.
  • 내가 원하는 시점에 그때 작용(lazy evaluation)
  • 컴퓨터 프로그래밍에서 느긋한 계산법(Lazy evaluation)은 계산의 결과값이 필요할 때까지 계산을 늦추는 기법이다. 두 가지 관련된 항목들이 있는데 지연 계산법과 최소 계산법이다.
  • 느긋하게 계산하면 필요없는 계산을 하지 않으므로 실행을 더 빠르게 할 수 있고, 복합 수식을 계산할 때 오류 상태를 피할 수 있고, 무한 자료 구조를 쓸 수 있고, 미리 정의된 것을 이용하지 않고 보통 함수로 제어 구조를 정의할 수 있다.
  • 느긋한 계산법을 사용하는 언어들은 “이름으로 호출”하거나 “필요할 때 호출”하는 계산 전략을 사용하는 것으로 나눌 수 있다. 하스켈과 같은 대부분의 실제 느긋한 언어들은 성능상의 이유로 “필요할 때 호출” 전략을 사용한다. 그러나 느긋한 계산법을 이론적으로 표현한 것들은 간편하게 “이름으로 호출”하기도 한다.

map

map 기본 문법

map(f, iterable) #mapobject를 반환한다. map은 함수와 iterable을 받는다.
  • 특정한 f(x)를 적용하여 새롭게 값을 뽑아내는 것. 이것을 선형대수에서는 사상이라고 한다.

ex)

li = [2, 3, 4, 5] # 여기에 있는 값을 제곱을 하여 하나씩 뽑아내보자.
m = map(lambda x: x**2, li)
next(m)
  • 맵에서 나온것 맵객체 필터에서 나온건 필터객체 이건 generator 객체에 포함되고 이건 또 iterator에 포함된다. 따라서 generator로 순회할 수 있다. iterator는 포문을 쓸 수 있으므로 map과 filter 역시 포문을 쓸 수 있다.

filter와 map을 함꼐 사용하여 풀어야 하는 문제

li = [ 2, 3, -5, 6, -2, 1, -10] # 양수를 골라내어 제곱한 값을 리스트로 만드시오

a = list(map(lambda x: x**2 , filter(lambda y: y>0, li)))

reduce

자료구조 (list,tuple)를 연산을 통해서 단 하나의 값으로 만드는 함수이다.
reduce는 내장함수가 아니므로 import를 해서 불러줘야한다.

from functools import reduce
help(reduce) 	#함수는 기본적으로 이름, 인자 , 반환값을 꼭 적어줘야한다.
	reduce(function, sequence[, initial]) -> value
	"""
	여기서 function 에는 람다가
	sequence에는 자료구조(iterable)이 들어갈 것이고 initial은 초기값이 들어갈 것이다.
	그리고 return 값으로는 하나의 value가 나와야 한다.
	"""

# reduce는 기본적으로 2개의 인자를 받는다.

li = [2, 3, -5, 6, -2, 1, -10]

result = reduce(lambda x,y : x+y, li)
result = reduce(lambda x,y: x+y, li, 100) # 100이 초기 x에 들어가도록 초기값 설정이 가능하다.

list의 최대 요소 구하기

li = [3,6,8,-10,2,1, 100, 50, 46, -47]
from functools import reduce
result = reduce(rambda x,y : x if x>y else y, li) (삼차다항식이용)

문자수 세기

li =[“a”, “b”, “a”, “b”, “b”, “a”, “c”, “a”]가 주어졌을 때 dic ={‘a’:4, ‘b’:3, ‘c’:1} —->크롤링해서 좋아요 혹은 싫어요 핸들링 할 때 사용

위와 같이 dictionary를 뽑아내자.

  • 첫번쨰 참고 : 파이썬의 함수는 식이므로 무조건 값을 반환(None도 반환)

  • 두번째 참고 : 논리 연산을 할 때 마지막으로 참조한 값을 반환한다.[1,2] or [] —> [1,2]라는 값을 반환한다.

  • dic.get(“a”,0) + 1 —> value로 활용하고

  • dic.update({“a”:3, “b” : 4})

  • 초기값 딕셔너리

import reduce
li =["a", "b", "a", "b", "b", "a", "c", "a"]
result  = reduce(lambda dic,cha : dic.update({cha : dic.get(cha,0)+1}) or dic, li, {}) 

dic.update는 None를 반환하므로 false이다 or dic을 통해 dic이 다시 위로 올라가도록 한다.