people.asSequence() // 원본 컬렉션을 시퀀스로 변환
.map(Person::name)
.filter { it.startsWith("A") } // 시퀀스도 컬렉션과 동일한 API 제공
.toList() // 결과 시퀀스를 다시 리스트로 변환
- map이나 filter같은 컬렉션 함수들은 결과 컬렉션을 즉시 생성한다.
- 이는 컬렉션 함수를 연쇄하면 매 단계 마다 계산 중간 결과를 새로운 컬렉션에 담는다는 의미이다.
- 연산을 효율적으로 사용하기 위해선 각 연산이 컬렉션을 직접 사용하는 대신 시퀀스를 사용하게 만들어야 한다.
[Sequence]
- 해당 시퀀스를 사용 시 중간 임시 컬렉션을 사용하지 않고 컬렉션 연산을 연쇄하는 것이 가능하다.
- Kotlin의 지연 계산 시퀀스는 Sequence 인터페이스에서 시작한다.
- Sequence 안에는 iterator이라는 메서드를 통해 시퀀스로부터 원소 값을 얻을 수 있다.
- 그 인터페이스 위에 구현된 연산이 계산을 수행하는 방법에서 장점이 생긴다.
- 중간 처리 결과를 저장하지 않고도 연산을 연쇄적으로 적용해서 효율적으로 계산을 수행할 수 있다.
- asSequence 확장 함수 호출 시 어떤 컬렉션이든 시퀀스로 변경할 수 있으며, 이를 리스트로 만들 떄는 toList를 활용한다.
- 시퀀스에 대한 연산을 지연 계산 하기 때문에 실행하게 만드려면 시퀀스의 원소를 하나씩 이터레이션하거나, 리스트로 변환해야 한다.
(1) 시퀀스 연산 실행: 중간 연산과 최종 연산
listOf(1, 2, 3, 4).asSequence()
.map { print("map($it)"); it * it }
.filter { print("filter($it)"); it % 2 == 0 }
.toList()
// map(1) filter(1) map(2) filter(4) map(3) filter(9) map(4) filter(16)
println(listOf(1, 2, 3, 4).asSequence()
.map {it * it}.find { it > 3 })
// 4
- 시퀀스에 대한 연산은 중간 연산과 최종 연산으로 나뉜다.
- 중간 연산은 항상 지연계산 되며, 이는 다른 시퀀스를 반환한다.
- 직접 연산의 경우 map을 먼저 수행하여 시퀀스를 얻고, 그 시퀀스에 대해 filter를 수행할 것이다.
- 시퀀스의 경우 모든 연산은 각 원소에 대해 순차적으로 적용된다. 즉, 첫 번째 원소가 처리 된 후, 두 번째 원소가 처리된다.
- 원소에 연산을 차례로 적용하다가 결과가 얻어지면 그 이후의 원소에 대해서는 변환이 이루어지지 않을 수 있다.
- 위 예제에서 같은 연산을 시퀀스가 아니라 컬렉션에 수행하면, map이 먼저 평가되어 최초 컬렉션의 모든 원소가 변환된다.
- 하지만 시퀀스에 수행했기 때문에, 원소 중 일부의 계산은 이루어지지 않는다.
(2) 시퀀스 만들기
val naturalNumbers = generateSequence(0) { it + 1 }
val numbersTo100 = naturalNumbers.takeWhile { it <= 100 }
println(numbersTo100.sum()) // 모든 지연 연산은 'sum'연산을 계산할 때 수행한다.
// 5050
fun File.isInsideHiddenDirectory() = generateSequence(this){it.parentFile}.any {it.hidden}
val file = File("/Users/svtk/.HiddenDir/a.txt")
println(file.isInsideHiddenDirectory()) // true
- generateSequence 함수를 통해서도 시퀀스를 만드는 것이 가능하다.
- 이 함수는 이전의 원소를 인자로 받아서 다음 원소를 계산한다.
- 위 예제에서 naturalNumbers와 numbersTo100은 모두 시퀀스이며, 연산을 지연 계산한다.
- 최종 연산을 수행하기 전까지는 시퀀스의 각 숫자는 계산되지 않는다.
- 객체의 조상으로 이루어진 시퀀스를 만들어내야 한다. 어떤 객체의 조상이 같은 타입이고, 모든 조상의 시퀀스에서 특성을 알고 싶을 때가 있다.
- 여기서도 첫 번쨰 원소를 지정하고, 시퀀스의 한 원소로부터 다음 원소를 계산하는 방법을 제공함으로써 시퀀스를 만든다.
'Kotlin in Action' 카테고리의 다른 글
5. [5] 수신 객체 지정 람다 (0) | 2024.02.25 |
---|---|
5. [4] 자바 함수형 인터페이스 활용 (0) | 2024.02.25 |
5. [2] Collection 함수형 API (0) | 2024.02.25 |
5. [1] 람다 식과 멤버 참조 (0) | 2024.02.25 |
3. [6] 코드 다듬기: 로컬 함수와 확장 (0) | 2024.02.22 |