flatMap()이란?
map의 모나드 버전.
flatMap()
을 통해 List를 평면화를 거쳐 새로운 List를 반환시킬 수 있습니다.
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
return flatMapTo(ArrayList<R>(), transform)
}
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
for (element in this) {
val list = transform(element)
destination.addAll(list)
}
return destination
}
flatMap()
함수를 보면 수신객체인 인자 T를 받아 새로운 List를 반환합니다.
Iterable<R>을 그대로 합쳐서 return 하면 2차원 List가 되겠지만, flatMapTo()
에서 Iterable<R>과 Iterable<T>를 flatten하는 작업을 거칩니다.
ArrayList를 하나 생성하고 Iterable<T> 전체탐색을 하면서 람다를 전부 실행한 결과인 1차원 List를 return합니다.
즉, flatMap()
을 통해 두개의 List를 람다로 변형한 형태로 합친 하나의 List로 결과로 받을 수 있습니다.
예제 1.
중복되지 않는 조합인 [1a, 1b, 1c, 1d, 2a, 2b, 2c, 2d, 3a, 3b, 3c, 3d, 4a, 4b, 4c, 4d]를
[1, 2, 3, 4], [a, b, c, d] 두개의 List를 가지고 flatMap()
을 사용하여
만들 수 있습니다.
import org.junit.jupiter.api.Test
class CollectionTest {
@Test
fun flatMapTest() {
val ints = (1..4) // [1, 2, 3, 4]
val strings = listOf("a", "b", "c", "d")
val flatMapList = ints.flatMap { int ->
strings.map { string ->
"$int$string"
}
}
println(flatMapList) // [1a, 1b, 1c, 1d, 2a, 2b, 2c, 2d, 3a, 3b, 3c, 3d, 4a, 4b, 4c, 4d]
}
}
먼저, flatMap()
의 람다에서는 결과로 List를 반환해 주어야 합니다.
즉, flatMap()
람다의 결과로 원하는 값인 int와 string을 가진 list를 반환해 주면 원하는 결과를 얻게 됩니다.
예제 2.
import org.junit.jupiter.api.Test
class CollectionTest {
@Test
fun flatMapTest() {
val list = listOf(listOf(1,2,3,4), listOf(5, 6, 7, 8), listOf(9, 10, 11, 12))
// val flatMap = list.flatMap { it }
val flatten = list.flatten()
println(flatten) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
}
}
같은 원리를 이용하여 flatMap()
을 이용하면 2차원 배열을 평면화 시킬 수 있습니다.
2차원 List인 list를 flatMap해주면 람다의 인자로 각각의 List가 들어오게 되는데,
List의 각각의 요소를 하나의 List로 합쳐서 Return 해줍니다.
또한, 람다식을 그대로 return하는 것이라면 list.flatMap { it } -> list.flatten()으로 간단하게 사용할 수 있습니다.