코틀린의 장점 중 하나가 자바에서 수작업 해야 했던 부분을 함수로 제공한다는 점이다. if로 null 체킹을 자주 한다거나, for문을 돌려 무언갈 확인할 때 무언가 불편했다. 조금 더 코틀린스러운 코딩을 하기 위해 함수들을 살펴보기로 했고, 그 중에서도 Collections에서 쓸 수 있는 Filter 함수에 관하여 간단히 적어보기로 했다.


지금 먹고 싶은 저녁 메뉴로 String 리스트를 만들었다. 사실 순대를 제일 먹고 싶은데 안 어울려서 뺐음.

val dinnerList = listOf("Pizza", "Risotto", "Pasta", "Hamburger")

이번 예제는 리스트를 필터링 한 후에 로그로 출력한 값을 기록했다.(출력에 필요한 코드는 생략) 단순히 조건을 지정한 후 판단하는 Filter 뿐 아니라 다양한 기능을 수행하는 필터들이 있다.


List<String> 에서의 필터 사용

Filter

dinnerList.filter {
    it.startsWith("P")
}
// [Pizza, Pasta]

먼저 가장 기초가 되는 filter이다. Boolean 값에 따라 필터링을 할지 안 할지 결정한다. 위의 경우에는 “P”로 시작하는 항목만 true이고, 이 값들만 필터링된다.


FilterNot

dinnerList.filterNot {
    it == "Pizza"
}
// [Risotto, Pasta, Hamburger]

filterNot은 말 그대로 조건이 아닌 경우에만 남길 때 사용하는 함수이다. 가독성이 걱정될 때 적절히 사용하면 로직을 보기 좋게 정리할 수 있을 것이다.


FilterIndexed

dinnerList.filterIndexed { index, s ->
    index == 3
}
// [Hamburger]

인덱스를 통해 처리하고 싶을 때에는 filterIndexed를 통해 인덱스와 값을 각각 받을 수 있다.



List<Any?> 에서의 필터 사용

리스트에 null이 포함되어 있는 경우를 살펴보자.

val diNullList = listOf("Pizza", null, "Risotto", "Pasta", "Hamburger")


FilterNotNull

Notnull String에서 사용할 수 있는 it.startsWith("P") 와 같은 함수를 사용할 수 없어 컴파일되지 않을 것이다.


아래 예제는 간단한 예제이므로 it?.startsWith("P") ?: false 와 같이 사용할 수도 있지만, 필터를 통해 null값인 경우를 제외하고 시작할 수도 있다. filterNotNull 을 사용하면 null 값을 제외한 List를 반환받는다. 이 리스트를 가지고 다시 필터링 할 수 있다.

diNullList.filterNotNull().filter {
    it.startsWith("P")
}
// [Pizza, Pasta]


FilterIsInstance

Any? 리스트가 있을 때 역시 String에서만 사용하는 함수를 사용할 수 없다.

val diNullList = listOf("Pizza", null, "Risotto", 100, "Pasta", "Hamburger")

Int가 포함되어 있기 때문에 filter 안에서 if (it is String)과 같은 if문을 한번 거치게 된다. 매번 타입 체크를 하게 된다면 참 번거로운 일일테니 필터로 걸러주자.

diNullList.filterIsInstance<String>().filter {
    it.startsWith("P")
}

결론

Filter 함수는 어떤 새로운 기능의 필터를 제공하다기보다는 사용자가 조금 더 간편하게 코딩하도록 돕는 필터였다. 간단한 예제로 사용해보긴 했지만, 실제로는 이것저것 중첩해서 쓰다보면 하나의 리스트에 걸려 있는 조건이나 수식이 많아 무거워지는 경우가 많았다. 이럴 때 필터 함수를 통해 알아보기 쉽게 원하는 값만 뽑아 쓸 수 있어서 편리했다.


References

  • https://tourspace.tistory.com/111