무효 클릭 IP 추적 중...
파이썬/파이썬 중급

[파이썬 중급] map, filter | zip + list comprehension

꼬예 2021. 5. 18.

이번시간에는 대표적인 Higher-Order function인 Map 과 Filter의 사용법을 알아 보겠습니다. 

뿐만아니라 zip과 list comprehension을 통해 Map과 Filter의 기능을 구현해보겠습니다.

(참고: Higher-Order function 은 인자로 함수를 받을 수 있는 function을 말한다.)

 

 

Map

map 함수는 첫번째 인자로 function 을 넣고, 두번째 인자에는 임의의 iterable들 을 넣을 수 있습니다.

(참고로 iterable은 for문을 돌릴 수 있는 객체를 의미한다.)

*iterables 는 여러개가 올 수 있다는 것을 의미합니다. 즉 iterable이 1개가 와도되고 2개 또는 그 이사잉 와도 된다는 뜻입니다. (*asterisk 표현에 대한것은 이전 포스팅에 설명하였으니 참조바랍니다.)

 

자세한사항은 코드로 확인해보겠습니다. 

l = [2, 3, 4]

def sq(x):
    return x**2

print(map(sq, l))
print(list(map(sq, l)))

output :

앞서 정의한대로 첫번째인자로는 함수 여기선 sq라는 함수를 지정했습니다. 두번째는 *iterators 여기선 대표적인 iterator중 하나인 리스트 1개를 넣었습니다.'

 

map만 이용하면 위와같이 객체 형태로 값을 반환하기 때문에 우리가 눈으로 보기위해서는 list를 감싸주어야 합니다!

 

이번에는 iterator가 두개 들어오는 경우를 보겠습니다. 

두개의 iterable을 사용할때는 몇가지 주의해야할점이 있는데요. 코드를 통해 확인해보겠습니다.

l1 = [1, 2, 3]
l2 = [10, 20 , 30] 

def add(x, y):
    return x + y 

list(map(add, l1, l2))

우선 두개의 iterable을 인자로 받게되면 함수도 두개의 인자를 받는 함수를 지정해야 합니다. 

output :

두개의 인자가 지정된 함수에의해 연산을 하고 하나의 iterable 형태가 되는것을 확인할 수 있습니다.

 

지금까지는 두개의 iterable의 갯수가 같은 상황에서만 연산을 했는데요 둘중 하나가 더 크거나 작으면 어떻게 연산을 할까요?

l1 = [1, 2, 3]
l2 = range(10)
def add(x, y):
    return x + y 

list(map(add, l1, l2))

output :

 

코드를 보시면 아시겠지만 l1 은 3개 l2 는 10개 입니다. 

그런데 결과는 3개가 나왔죠.

즉, 작은 갯수를 기준으로 연산을 한후 나머지 값들은 버린다는 것을 알 수 있습니다. 

 

lambda 함수 이용

l1 = [1, 2, 3]
l2 = [10, 20 , 30] 
print(list(map(lambda x, y : x + y, l1, l2)))

output :

첫번째 인자로 함수가 들어올수 있다고 했었죠?

그렇다면 lambda 함수를 이용할 수도 있겠네요.

복잡한 함수가 아니라면 lambda를 통해 더 깔끔한 코드를 쓸수있으니 참고하세요!

 

 

filter

filter라는 이름에서 느낌이 오듯이 특정한 조건에 상응하는 값을 골라내는 함수라고 볼 수있습니다. 

사용방법으로 

 

filter(func, iterable)

 

첫번째 인자로 함수, 두번째 인자로 iterable을 넣습니다. 

하지만 map과는 다르게 iterable 앞에 *가 없죠?

즉, iterable이 1개만 들어올 수 있다는 뜻입니다. 

 

코드를 통해 자세히 알아보죠

l = [0, 1, 2, 3, 4] 

print(list(filter(None, l)))

output :

filter의 기본적인 형태로 함수가 올 자리에 None이 왔습니다. 이건

특별한 조건을 정하지 않고 리스트내의 값에서 True False값을 찾아 True인값만 반환하겠다는 것입니다.

숫자 0만 false 이고 나머지는 True이기 때문에 숫자 0을 제외한 값들이 출력으로 나온걸 알 수 있습니다. 

 

이번에는 함수를 지정해볼까요?

l = [0, 1, 2, 3, 4]

def is_even(n):
    return n % 2 == 0

list(filter(is_even, l))

짝수를 찾기위한 함수를 만들었고 filter에 적용해보았습니다. 

여기선 짝수 조건에 성립하는 값만 True이니까 짝수 값만 return 되겠죠?

output :

lambda 함수 이용

마찬가지로 filter에서도 lambda 함수를 쓸수 있습니다.

l = [0, 1, 2, 3, 4]
list(filter(lambda x: x % 2 ==0, l))

output :

 

zip 과 list comprehension 사용

지금까지 배웠던 map과 filter기능을 zip 과 list comprehension을 통해 구현할 수있습니다. 

 

우선 간단하게 zip 과 list comprehension에 대해 알아보겠습니다. 

zip 은 단어느낌대로 zipper로 쭉 묶어주는 기능을 합니다. 

l1 = [1, 2, 3]
l2 = [10, 20, 30]
l3 = ['a','b','c']

print(list(zip(l1,l2,l3)))

output :

보시는것처럼 같은 인덱스에 위치한 값들을 튜플로 묶는것을 알 수있습니다. 

zip도 map과 filter처럼 객체를 반환하기 때문에 우리가 눈으로 보기위해선 list로 싸주어야 합니다. 

 

다음 코드는 어떤 output이 나올까요?

l1 = range(100)
l2 = 'abcd'

list(zip(l1,l2))

output :

map에서 살펴본거랑 비슷하죠?

l1은 100개이고 l2는 4개를 묶다보니 작은 거까지 묶고 나머지는 버리는 것을 알 수 있습니다. 

 

다음으론 list comprehension 을 알아보겠습니다. 

기본형태는 아래와 같습니다. 

in 뒤에는 iterable 그리고 나머지는 우리가 for문에서 쓰는 형태입니다. 

코드를 통해 알아보죠.

 

우리구현해볼 코드는 앞서 map을 통한 값인데요 해당 값을 zip과 list comprehension 을 이용해 똑같은 값을 얻어 보겠습니다. 

l1 = [1, 2, 3]
l2 = [10, 20, 30]

[x + y for x, y in zip(l1, l2)]

우선 zip을 통해 l1 ,l2 의 값을 인덱스 별로 튜플 형태로 만듭니다. 그값은 zip object 형태인 iterable이 될것입니다. 

그게 for문을 통해 x, y로 unpacking 이 되고 x + y 연산을 합니다. 

연산이 끝난 값은 마지막 리스트안에 차곡차곡 쌓이게 됩니다. 

output :

 

이번엔 filter를 이용한 코드인데요 .

해당 코드를 list comprehension을 통해서도 구현을 할 수있습니다. 

여기선 if라는 조건문이 새롭게 추가가되었는데요 제일 마지막에 위치합니다. 위치를 잘 지켜주시기 바랍니다. 

l = range(10)
[x**2 for x in range(10) if x**2 < 25]

output :

우리가 기존에 아는 for문을 이용하는 것과 같습니다. 

다만, if 위치가 조금 다르고 , 리스트를 둘러싸서 append를 할필요 없다는 점만 다르죠.

 

 

  • 트위터 공유하기
  • 페이스북 공유하기
  • 카카오톡 공유하기
이 컨텐츠가 마음에 드셨다면 커피 한잔(후원) ☕

댓글