본문 바로가기
Do it 코틀린 프로그래밍

코틀린 시퀀스

by 차누감 2020. 9. 5.

코틀린의 시퀀스(Swquence)는 순차적인 컬렉션으로 요소의 크기를 특정하지 않고, 나중에 결정할 수 있는 특수한 컬렉션입니다. 시퀀스는 처리 중에는 계산하고 있지 않다가 toList()나 count() 같은 최종 연상에 의해 결정됩니다.

 

요소 값 생성하기

generateSequence()로 생성하기

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

map이나 filter 같은 연산을 사용할 수도 있습니다.

    val squares = generateSequence(1) { it +1 }.map { it * it }
    println(squares.take(10).toList())  //  [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    val oddSquares = squares.filter { it % 2 !=0 }
    println(oddSquares.take(5).toList())  //  [1, 9, 25, 49, 81]

 

요소 값 가져오기

메서드 체이닝의 중간 결과 생성하기

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

 

asSequence() 사용 X. 중간 연산 값을 출력 가능

fun main(){
    val list1 = listOf<Int>(1, 2, 3, 4, 5)
    val listDefault = list1
        .map { println("map($it)"); it * it; }
        .filter { println("filter($it)"); it % 2 == 0 }
    println(listDefault)
}
//	결과
map(1)
map(2)
map(3)
map(4)
map(5)
filter(1)
filter(4)
filter(9)
filter(16)
filter(25)
[4, 16]

asSequence()를 통해 가져오기. (중간 연산 과정만드로 결과 도출할 수 없습니다.)

fun main(){
    val list1 = listOf(1, 2, 3, 4, 5)
    val listDefault = list1.asSequence()
        .map { println("map($it)"); it * it; }
        .filter { println("filter($it)"); it % 2 == 0}
        .toList()
    println(listDefault)
}
//	결과
map(1)
filter(1)
map(2)
filter(4)
map(3)
filter(9)
map(4)
filter(16)
map(5)
filter(25)
[4, 16]

 

asSequence()의 시간 성능

큰 요소에 대한 시간 성능을 살펴보기 위해 경과된 시간을 표시하도록 System.nanoTime() 이용하여 비교합니다.

fun main(){
    val listBench = (1..1_000_000).toList()
    timeElapsed{
        listBench
            .map { it + 1 }
            .first{ it % 100 == 0 }
    }
    timeElapsed{
        listBench
            .asSequence()
            .map { it + 1 }
            .first{ it % 100 == 0 }
    }
}

fun timeElapsed(task: () -> Unit){
    val before = System.nanoTime()
    task()
    val after = System.nanoTime()
    val speed = (after - before) / 1_000
    println("$speed ns")
}

//결과
14525 ns
5430 ns

asSequence를 사용하는 경우 비교적 짧은 시간에 수행된 것을 알 수 있습니다.

다만 작은 컬렉션에는 시퀀스를 사용하지 않는 것이 좋습니다. 왜냐하면 filter() 등은 인라인 함수로 설계되어 있는데, 시퀀스를 사용하면 람다식을 저장하는 객체로 표현되기 때문에 인라인 되지 않아 작은 컬렉션에는 오히려 좋지 않습니다. 또한 한 번 계산된 내용은 메모리에 저장하기 때문에 시퀀스 자체를 인자로 넘기는 형태는 사용하지 않는 것이 좋습니다.

 

댓글