Skip to content

지연 계산 컬렉션 연산

코틀린 표준 API인 filtermap은 리스트를 반환한다.

이는 메서드 체인시, 리스트를 2개를 만든다는 의미이다.

첫 리스트에는 map의 결과를 담고, 그 결과로 filter을 수행한다.

원소가 적다면 문제가 없겠지만, 수백만개 이상이 된다면 효율이 떨어진다.

(Lazy와 Eager의 성능은 무조건 이게 좋다라고 할수 없고 상황에 따라서 프로파일링 해봐야한다.)

kotlin
people.asSequence()
    .map(Person::name)
    .filter { it.startsWith("A") }
    .toList()

코틀린의 지연 계산 시퀀스는 Sequence 인터페이스에서 시작된다.

Sequence 안에는 iterator라는 단 하나의 메소드가 있다. 이 메소드를 통해 시퀀스로부터 원소 값을 얻을 수 있다.

Note

큰 컬렉션에 대해서 연산을 할때 시퀀스를 사용하는것을 규칙으로 삼아라. 종종 중간 컬렉션을 생성함에도 불구하고 즉시 계산 컬렉션이 효율적인 경우가 있다. 그러나 컬렉션에 들어있는 원소가 많으면 중간 원소를 재배열하는 비용이 더 커지기 때문에 지연 계산이 더 낫다.

시퀀스 연산 순서

시퀀스는 중간(intermediate) 연산과 최종(terminal) 연산으로 나뉜다.

kotlin
listOf(1,2,3,4).asSequence()
    .map {it * it }         // 중간 연산 1
    .filter { it % 2 == 0 } // 중간 연산 2
    .toList()               // 최종 연산
``

시퀀스는 중간 연산의 결과에 따라서 그 다음의 중간 연산 시퀀스가 실행되지 않을 수 있다.

예를 들어, 아래 코드에서 asSequence는 find의 조건에 맞는 원소를 찾게되면 이후의 연산은 실행하지 않는다.

반면에 컬렉션은 모든 원소에 대해 map을 실행한 뒤 리스트를 저장한 뒤 find를 수행하게 된다.

```kotlin
listOf(1,2,3,4).asSequence()
    .map { it * it }
    .find { it > 3 }

listOf(1,2,3,4)
    .map { it * it }
    .find { it > 3 }

이를 이용해 시퀀스를 수행할 때, 이를 이용해 불필요한 연산을 줄일 수 있다. 아래 코드에서 filter를 먼저하면 map연산은 "4,5"만 실행되지만 map을 먼저하면 전부 연산 후 filter가 연산되므로 불필요한 연산을 하게 된다.

kotlin
listOf(1,2,3,4,5).asSequence()
    .filter { it > 3 }
    .map { it * it }
    .toList()

listOf(1,2,3,4,5).asSequence()
    .map { it * it }
    .filter { it > 3 }
    .toList()

Email: echo.youn@kakao.com