Day to_day

계속 헷갈려하던 map과 filter함수 개념 및 활용 본문

Python

계속 헷갈려하던 map과 filter함수 개념 및 활용

m_inglet 2022. 9. 23. 14:48
728x90
반응형

자바스크립트로 먼저 filter와 map에 대해서 배우면서 개념에 대해서 얼추 감을 잡긴 했지만 항상 헷갈려했었다.

이번에 파이썬으로 다시 배워보면서 개념과 활용까지 확실하게 잡고 갈 예정

 

def get_eng_title(row):
	split = row.split(',')
    return split[1]
    
eng_titles = [get_get_title(row) for row in movies]

 

위와 같은 예시가 있다고 보자. get_eng_title은 콤마를 기준으로 row를 나누어 row의 인덱스 1을 리턴하는 함수이다.

list comprehension으로 movies에 들어있는 row를 for문을 통해서 하나씩 가져오고, 아까 선언한 get_eng_title 함수에 하나씩 넣는 것이다.

그리고 나온 리턴 값을 다시 리스트로 만들었다.

 

for문은 하나씩 꺼내와서 함수에 차근차근 넣는 식으로 되어있기 때문에 만약 데이터가 클 경우 이런식으로 사용하면 시간이 너무 오래 걸릴 수가 있다.

 


map()

map(함수, 리스트)

map의 인자는 함수와 리스트가 들어간다.

map(f(x), list) 이런식으로 주어질때 list = [x,y,z]는 list = [f(x), f(y), f(z)] 즉 함수의 리턴 값으로 모두 반환이된다.

 

예시

movies = ['Harry Poter', 'Kings man', 'Tall girl']
get_title = lambda row: row.split()[1]
titles = map(get_title, movies)

모든 리스트 요소에 한꺼번에 적용이 되게 하기 위해서 map을 이용한다.

lambda 함수를 사용해서 row를 공백을 기준으로 split하고 그것의 인덱스 1의 요소를 가져와 다시 리스트를 만드는 과정이다. 위의 예시와 비교해 보면 훨씬 더 짧게 코드가 작성된 것을 알 수 있다.

 

하지만 여기서 print(titles)를 직접하면,

이러한 결과를 얻게된다. 사실 map함수의 결과는 list처럼 보이지만 사실 map이라는 타입을 가진다. 그래서 list로 감싸주지 않고 그냥 출력을 하게되면 위와같은 결과를 얻게되는 것이다.

 

그렇다면 왜 처음부터 list로 저장을 하지 않는 걸까?

→ 사용자가 원하는 원소를 부를때 그때 함수를 적용해서 반환한다.

만약 10만개의 리스트가 있다면 이것을 모두 함수에 넣어서 다 바꿔놔야하니까 효율적으로 사용하는것!

map으로 약속만 해놓고 사용한 원소에 대해서만 함수로 바꿔서 보내준다. 

 

그래서 print(list(titles))로 출력을 원할 때 '아~ 이 사용자가 모든 결과물을 리스트로 보길 원하는 구나!' 하고 map함수를 그때 적용 시키는 것!

 

 

map 함수 활용

# CSV 모듈을 임포트
import csv

def get_titles(books_csv):
    with open(books_csv) as books:
        reader = csv.reader(books, delimiter=',')
        get_title = lambda row: row[0]
        titles = map(get_title, reader)

        return list(titles) 
        #list로 감싸지 않고 map 자체로 리턴하면 연산이 되지 않은채로 파일이 닫히게 된다. 
        #그러면 map을 적용할 수 없으니 list로 감싸서 리턴


books = 'books.csv'
titles = get_titles(books)
for title in titles:
     print(title)

books_csv 파일을 열어주고 csv.reader를 통해서 읽는다.

익명 함수 lambda로 제목 부분만 얻고싶기 때문에 row[0]을 리턴하게둔다.

map으로 감싸서 함수(get_title)과 reader 리스트를 가지고 온다.

 

map함수를 사용하지 않으면 아래와 같은 for문을 이용해서 title list를 새롭게 만들었어야 했을 것이다.

title = []
for row in reader:
	titles.append(get_title(row))

 

return list(titles)

한가지 또 봐야할 것은 list로 감싸지 않고 map 자체로 리턴하면 연산이 되지 않은채로 파일이 닫히게 된다.

그러면 map을 적용할 수 없으니 list로 감싸서 리턴한다.

 


filter()

다음은 filter 함수!

filter(함수, 리스트) 

map함수와 같이 들어가는 인자는 같다.

 

근데 map에선 list = [f(x), f(y), f(z)] 로 나왔다면

filter는 함수를 적용했을때 내용이 True 라면 그 값을 반환한다.

그래서 만약 f(x)와 f(z)가 참이 나오고 f(y)가 거짓이 나왔다면 x와 z만 반환해주는 것

list = [x,z] 이렇게 말이다.

 

r_word = filter(starts_with_r, words)
print(r_word)

r로 시작하는 단어만 모두 리스트에 넣어서 print하고 싶을 때, filter함수를 사용할 수 있다.

하지만 위의 예시도 map 함수랑 비슷하게 아래와 같이 뜬다.

 

filter도 filter 타입을 갖고, 결과를 모두 보고 싶으면 list로 감싸서 print해줘야한다.

 

 

filter 함수 활용

def get_titles_of_long_books(books_csv):
    with open(books_csv) as books:
        reader = csv.reader(books, delimiter=',')
        # 함수를 완성하세요.
        is_long = lambda row: int(row[3]) > 250
        get_title = lambda row: row[0]
        
        long_books = filter(is_long, reader)
        long_book_titles = map(get_title, long_books)
        
        return list(long_book_titles)

is_long은 true or false가 나오게 하는 함수이고 get_title은 모든 리스트에 적용해줄 함수이다.

그래서 is_long에는 페이지가 250이상 이라는 조건을 넣어주고 true로 나온 그 값에서 첫번째 원소인 제목만 list에 넣어서 리턴해준다.

 

여기서 filter에서 map으로 넘어갈때 따로 list로 묶어서 보내줄 필요는 없다.

728x90
반응형
BIG
Comments