파이썬을 c처럼 짜다가, 이것 저것 기능을 알아가다 보니, 이렇게 짜면 코드가 단순해지겠네. 하는 것이 하나씩 있습니다. 그 중 하나는 filter입니다. 자바에서는 필터랑 람다랑 짝궁처럼 붙어다니기도 합니다. 파이썬에서도 마찬가지입니다.

 


 공식 문서에 따르면, filter는 function과, iterable을 받습니다. 대표적으로 iterable 한 것은 list가 있습니다. 예제를 몇 개 보도록 하겠습니다.

 

 

 먼저, func은 항상 True를 리턴합니다. 그리고 2번째 인자로 li를 넣었는데요. 여기에는 1, 2, 3, 4, 5가 저장되어 있습니다. 무엇이 나오는지 결과부터 보도록 하겠습니다.

 

 

 그대로 1, 2, 3, 4, 5가 나오게 됩니다. 이는 뭐가 되었던지 간에 항상 True가 리턴이 되었기 때문입니다. 1을 가도 참, 2를 가도 참, ..., 5로 가도 참값이니, list에 있는 전체 값이 나온 셈입니다. 사실, 저런 경우에는 func 대신에 None을 쓰거나, 아니면 그냥 list(li)를 하는 것이 좋아 보입니다. li에 있는 내용을 필터를 안 거치기 때문입니다.

 

 

 반면에, 이것은 어떨까요? func이 항상 False를 리턴합니다.

 

 

 그러면, 아무 것도 나오지 않습니다. 계속 돌아도 False가 나오기 때문입니다.

 

 

 원소에 있는 내용 중에 짝수만 추출해 봅시다. 그러면 func에 x % 2의 값이 0이면 참 값을 리턴하게 하면 됩니다.

 

 

 결과는 2, 4만 나옵니다.

 


 이제 조금 더 실용적인 예제로 가 보겠습니다. 파이썬 bfs 코드를 검색해 보면 list의 extend 메서드를 많이 썼다는 것을 알 수 있는데요. 예를 들어서, 리스트 a에 있는 모든 요소를 리스트 b에 추가할 때 많이 씁니다. 해당 요소와 연결이 되어 있는 노드들을 모두 큐에 추가할 때도 이용해 먹을 법 합니다. 그러니 많이 쓰셨을 겁니다. 틀린 방법은 아니지만, 필터를 거치지 않고 extend를 쓰면 한 노드가 중복해서 들어갈 수 있습니다. visit가 된 것은 빼고 넣어야 하는데요. 그 처리를 어떻게 해야 할까요? 

 

 방문한 노드는 넣으면 안 됩니다. 그러면, 문제의 함수를 아래와 같이 작성할 수 있습니다.

 

 

 visit set을 둡니다. 리스트가 아닌 set으로 처리하는 이유는, list에서 in 연산은 O(size)만큼 들기 때문입니다. 그에 비해서, set은 매우 빠른 속도로 해당 key가 있는지 찾을 수 있습니다. 우리는 li에 있는 원소들 중에서, visit에 없는 원소들만 꺼내 올 겁니다. 그럴려면, x가 visit에 없어야 겠지요. 5번째 줄은 그러한 역할을 수행합니다.

 

 

 결과를 보면 2, 4만 나왔음을 볼 수 있습니다. 그런데, 너무 장황해 보입니다.

 

 

 람다 식을 쓰면 간결해 집니다. 1번째 인자에 x: x not in visit를 썼는데요. 이는 단지, visit에 없으면 참을 리턴하는 익명 함수를 의미합니다. 이런 형태는 필터를 할 때도, 정렬할 때에도 생각보다 많이 보이는 편입니다. 당장, 이 문서만 봐도, 비교 기준이 되는 key를 리턴하기 위한 람다가 쓰임을 알 수 있습니다. 그러니 알아두면 좋을 듯 싶습니다.

 

 

 결과는 위와 같습니다.

 


 짝수만 추출 할 때 아래와 같이 쓸 수도 있을 겁니다.

 

 이런 식으로요. 이것의 의미는 단지, x % 2의 값이 0이라면, 즉 x가 2의 배수라면 True를 리턴합니다. 이 익명함수의 리턴값이 참이라면, 추출이 되는 형태입니다.

 

 

 결과는 위와 같습니다. 그런데, 사실, 이것은 list 컴프리헨션을 써도 됩니다.

 

 

 이렇게요. for in 뒤에 if문을 썼음을 알 수 있습니다. 이것은 순서대로 li를 순회하면서, 2의 배수인 것만 뽑은 것들로 이루어진, 배열을 만들라는 의미입니다. 1은 아니고, 2는 맞습니다. 그리고 3이 아니고, 4는 맞습니다. 5는 2로 떨어지지 않습니다. 따라서, 2와 4로만 이루어진 배열 filtered가 생성됩니다.

 

 

 결과는 위와 같습니다.