코틀린

Do it! 코틀린 프로그래밍, 09-5 시퀀스 활용하기

조요피 2021. 9. 26. 23:34

코틀린의 시퀀스(Sequence)는 순차적인 컬렉션으로 요소의 크기를 특정하지 않고, 나중에 결정할 수 있는 특수한 컬렉션.

예를 들어 특정 파일에서 줄 단위로 읽어서 요소를 만들때 해당 파일의 끝을 모르면 줄이 언제 끝날지 알 수 없는 경우가 있는데 이럴 때 사용할 수 있다.

따라서 시퀀스는 처리 중에는 계산하고 있지 않다가 toList()나 count() 같은 최종 연산에 의해 결정된다.

요소 값 생성하기

generateSequence()로 생성하기

fun main() {
    // 시드 값 1을 시작으로 1씩 증가하는 시퀀스 정의
    val nums: Sequence<Int> = generateSequence(1) {it + 1}
    // take()를 사용해 원하는 요소 개수만큼 획득하고 toList()를 사용해 List 컬렉션으로 반환
    println(nums.take(10).toList())

    val sq = generateSequence(1) {it + 1}.map { it * it }
    println(sq.take(10).toList())

    val sq2 = sq.filter { it % 2 != 0 }
    println(sq2.take(5).toList())
}

//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
//[1, 9, 25, 49, 81]

요소 값 가져오기

중간 연산 결과 없이 한 번에 끝까지 연산한 후 결과를 반환하려면 asSequence()를 사용할 수 있다.

filter나 map을 메서드 체이닝해서 사용할 경우 순차적 연산이기 때문에 시간이 많이 걸릴 수 있지만 asSequence()를 사용하면 병렬 처리되기 때문에 처리 성능이 좋아진다.

fun main() {
    // 메서드 체이닝
    val list1 = listOf(1, 2, 3, 4, 5)
    val list2 = list1.map { println("map($it)"); it * it }.filter { println("filter($it)"); it % 2 == 0 }
    println(list2)

    println("==========================================")

    // asSequence
    val listSq =
        list1.asSequence().map { println("map($it)"); it * it }.filter { println("filter($it)"); it % 2 == 0 }.toList()
    println(listSq)
}

//map(1)
//map(2)
//map(3)
//map(4)
//map(5)
//filter(1)
//filter(4)
//filter(9)
//filter(16)
//filter(25)
//[4, 16]
//==========================================
//map(1)
//filter(1)
//map(2)
//filter(4)
//map(3)
//filter(9)
//map(4)
//filter(16)
//map(5)
//filter(25)
//[4, 16]

asSequence()를 사용하면 했을 경우 연속적으로 map과 filter가 각각 수행됐으며 최종 결과는 toList()에 의해 만들어진다.

즉, map의 수행 결과를 새로운 List에 만들고 이것을 다시 짝수인지 판별해 리스트를 만드는 과정이 생략된 것.

시퀀스를 이용한 피보나치

fun main() {
    val fibonacci = generateSequence(1 to 1) {it.second to it.first + it.second}.map{it.first}
    println(fibonacci.take(10).toList())
}

//[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

* 소수 출력도 있음!