몰?.루();

코틀린 filter, map 사용법 본문

프로그래밍/안드로이드, 코틀린

코틀린 filter, map 사용법

toonraon 2022. 2. 23. 19:13

코틀린에는 배열에 쓸 수 있는 여러가지 컬렉션 관련 함수들이 있는데 그 중에서 가장 유용한 게 filter와 map이 아닐까 싶습니다.

 

List, MutableList, 일반적인 Array, ArrayList 등 다양한 컬렉션에서 쓸 수 있습니다.

filter 사용법

fun main() {
    val arr = listOf(1, 2, 3, 4, 5, 6, 7, 8)

    val arr2 = arr.filter { it % 2 == 0 } // arr에서 짝수인 애들만 남겨서 arr2에 저장

    println(arr) // [1, 2, 3, 4, 5, 6, 7, 8]
    println(arr2) // [2, 4, 6, 8]
}

filter는 이름대로 특정 원소만 필터링해서 return하는 역할입니다.

원래 변수엔 영향을 주지 않습니다. (그렇기에 값을 바꿀 수 없는 List에도 사용 가능한 것입니다.)

 

map 사용법

fun main() {
    val arr = listOf(1, 2, 3, 4, 5, 6, 7, 8)

    val arr2 = arr.map { it * 2 } // arr에서 각각 2를 곱해서 arr2에 저장

    println(arr) // [1, 2, 3, 4, 5, 6, 7, 8]
    println(arr2) // [2, 4, 6, 8, 10, 12, 14, 16]
}

map은 원래의 값에 내가 원하는대로 변형을 한 값을 return하는 역할입니다.

마찬가지로 원래 변수엔 영향을 주지 않습니다.

람다식에 익숙하지 않다면 { it * 2 }이 생소해보일 수 있는데 쉽게 말해서 그냥 it는 arr의 원소 하나하나를 말합니다. 원래대로라면 for문을 돌면서 arr[i] 이런 식으로 접근해야하지만 그냥 it을 통해 arr[i]를 대체한다고 보면 됩니다.

자세한 것은 람다식에 대해 검색해보면 알 수 있으실 겁니다.

 

예제

filter와 map은 따로 쓰이기도 하고, 같이 쓰이는 경우도 많습니다.

예를 들어 백준 같은 곳에서 문제를 풀 때 이런 입력이 들어오는 경우가 있습니다.

101011101010001101

이 값들을 Boolean 배열에 저장해서 여차저차 계산을 해야한다고 합시다.

문제는 이 값들은 String 형태로 들어오기 때문에 한 줄을 통째로 문자열로 읽은 다음에, 하나하나 1과 0으로 떼어 놓은 다음에, Boolean 값으로 변환해야합니다.

 

C++같은 다른 언어 같으면 벌써 사람들이 for문 입력하려고 f랑 o 위에 손가락이 가있겠지만 코틀린 사용자들은 고작 이런 일에 for를 쓰지 않습니다. (물론 코드 내부적으론 for를 쓰겠지만 프로그래머가 직접 반복문을 타이핑 하지 않는다는 뜻입니다.)

 

fun main() {
// 입력: 101011101010001101 (문자열)
    val arr = readLine()!!.split("").filter { it.isNotBlank() }.map { it == "1" }
    println(arr) // [true, false, true, false, true, true, true, false, true, false, true, false, false, false, true, true, false, true]
}

뭐 출력이나 main 같은 걸 제외하면 사실 코드는 딱 한 줄 뿐입니다.

val arr = readLine()!!.split("").filter { it.isNotBlank() }.map { it == "1" }

이거 한 줄만으로 다음 기능들을 모두 하고 있는 겁니다.

  • 사용자로부터 input을 받고
  • 문자열을 각각 하나씩 쪼개고
  • 그 중에서 라인 개행 같은 거는 없애고 ("1", "0"만 남기고)
  • "1"은 true로, 나머진 false로 변환해서
  • 배열을 만들고 그 배열에 저장

 

이해를 돕기 위해 여러 줄에 풀어서 쓰면 다음과 같습니다.

fun main() {
    val input = readLine()!! // "101011101010001101"
    val splits = input.split("") // ["", "1", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "0", "0", "0", "1", "1", "0", "1", ""]
    val notBlankOnly = splits.filter { it.isNotBlank() } // ["1", "0", "1", "0", "1", "1", "1", "0", "1", "0", "1", "0", "0", "0", "1", "1", "0", "1"]
    val arr = notBlankOnly.map { it == "1" } // [true, false, true, false, true, true, true, false, true, false, true, false, false, false, true, true, false, true]
}

split("")하고 나서 나온 배열의 처음과 끝에 ""라는 쓸모없는 blank가 들어있는데 이걸 지우기 위해 filter를 사용하고 filter 안에서는 String의 isNotBlank() 함수를 이용해서 ""는 지우는 모습입니다.

그리고 마지막으로 "1"은 true로, 나머진 false로 변환해주기 위해 map을 사용해서 간단한 비교식(it == "1")을 통해 Boolean값으로 원소들을 전부 바꿔주는 모습입니다.

 

참고로 위에서 쓰인 함수들은 전부 다 코틀린 기본 기능이므로 아무것도 import 할 필요가 없습니다.

Comments