개요
- map, filter의 연쇄적 호출 → 결과 컬렉션을 즉시 생성
- 컬렉션 함수 연쇄 사용 → 매 단계마다 계산 중간 결과를 새로운 컬렉션에 임시로 저장
- 시퀀스 → 중간 임시 컬렉션을 사용하지 않고 연쇄 연산을 진행하는 방법을 제공
- 시퀀스 → Sequence 인터페이스에서 시작
- Sequence 인터페이스에는 iterator라는 메서드만 있음
- 시퀀스의 원소 → lazy 하게 연산
- asSequence 확장 함수를 호출하면 어떤 컬렉션이든 시퀀스로 바꿀 수 있음
- 원소를 인덱스를 사용해 접근해야 한다면 시퀀스를 다시 컬렉션으로 변환해야 함
시퀀스 연산 실행: 중간 연산과 최종 연산
중간 연산
최종 연산
- 최초 시퀀스에 대해 변환을 적용한 시퀀스에서 일련의 계산을 수행해 얻은 객체
최종 연산이 없는 시퀀스
fun main() {
println(
listOf(1, 2, 3, 4)
.asSequence()
.map {
print("map($it)")
it * it
}
.filter {
print("filter($it)")
it % 2 == 0
}
)
}
- Sequence의 원소가 출력되는 대신 Sequence 객체 자체에 대해 출력됨
- map, filter 연산이 지연됐기 때문
- map, filter 연산은 최종 연산이 호출될 때 적용됨
최종 연산 적용
fun main() {
println(
listOf(1, 2, 3, 4)
.asSequence()
.map {
print("map($it)")
it * it
}
.filter {
print("filter($it)")
it % 2 == 0
}.toList()
)
}
- 시퀀스에 대한 map, filter 연산 → 각 원소에 대해 순차적으로 적용
- 원소에 연산을 차례대로 적용하다가 결과가 얻어지면 그 이후의 원소에 대해서는 변환이 이뤄지지 않을 수 있음
중간 연산 중 종료
fun main() {
println(
listOf(1, 2, 3, 4)
.asSequence()
.map { it * it }
.find { it > 3 }
)
}
- 지연 계산으로 인해 원소 중 일부의 계산이 이뤄지지 않음
연산 수행 순서에 따른 성능 차이
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(
Person("Alice", 29),
Person("Bob", 31),
Person("Charles", 31),
Person("Dan", 21)
)
println(
people
.asSequence()
.map(Person::name)
.filter { it.length < 4 }
.toList()
)
println(
people
.asSequence()
.filter {it.name.length < 4}
.map(Person::name)
.toList()
)
}
- 두 시퀀스의 결과는 같음
- 하지만 중간 연산에서 변환 횟수가 다름

- filter를 먼저 수행하면 필요없는 원소가 먼저 걸러지기 때문에 성능이 좀 더 좋음
시퀀스 만들기
시퀀스를 만드는 방법 : asSequence(), generateSequence()
- generateSequence함수 → 이전의 원소를 인자로 받아 다음 원소를 계산
fun main() {
val naturalNumber = generateSequence(0) { it + 1 }
val numberTo100 = naturalNumber.takeWhile { it <= 100 }
println(numberTo100.sum())
}
- naturalNumber, numberTo100 → 최종 연산 전까진 시퀀스의 각 수는 연산이 지연됨
조상 디렉터리의 시퀀스를 생성하고 사용하기
import java.io.File
fun File.isInsideHiddenDirectory() =
generateSequence(this) { it.parentFile }.any{ it.isHidden }
fun main() {
val file = File("/Users/svtk/.HiddenDir/a.txt")
println(file.isInsideHiddenDirectory())
}