컬렉션 API 중, map이나 filter 같은 함수는 결과 컬렉션을 즉시 생성합니다.
이것은 즉, 컬렉션 함수를 연쇄하면 매 단계마다 중간 계산 결과를 새로운 컬렉션에 임시로 저장하고 있다는 말입니다.
반면에, 시퀀스(sequence)를 사용하면 중간 임시 컬렉션을 사용하지 않고도 컬렉션 연산을 연쇄할 수 있습니다.
sequences 의 여러 단계 처리는 전체 단계가 처리된 결과가 요구됬을 때에 실제 연산이 일어나며 느리게(나중에) 처리됩니다. (executed lazily)
동작 수행의 순서 또한 다릅니다. Sequence 은 각각 하나의 element 에 대해 모든 단계를 수행합니다.
Iterable 은 전체 collection 에 대해 각 단계의 수행을 완료하고 다음 단계로 넘어갑니다.
따라서, sequence 는 중간 단계의 결과에 대한 처리를 피할 수 있게 해주며, collection 전체 처리에 대한 수행 성능이 향상됩니다.
하지만 크기가 작은 collection 이나 단순한 연산 동작에 대해서는 오히려 불필요한 오버헤드가 생길 수 있습니다.
그러므로 어느 경우에 Sequence 나 Iterable 이 나을지 적절한 선택을 해야 합니다.
asSequence()
List, Set 같은 Iterable object 를 이미 가지고 있다면 asSequence() 함수를 통해 sequence 를 생성합니다.
data class Person (val name: String, val age:Int)
val person = ArrayList<Person>()
person.add(Person("김바다", 35))
person.add(Person("김하늘", 38))
person.add(Person("김소금", 24))
person.add(Person("박강남", 38))
person.add(Person("최무선", 65))
person.add(Person("이우진", 28))
person.add(Person("이용규", 34))
person.add(Person("박곰탕", 66))
println(person.asSequence()
.map{it.name}
.filter{it.startsWith("김")}
.toList())
//[김바다, 김하늘, 김소금]
전체 연산을 수행하면서 중간 결과를 저장하는 컬렉션이 생기지 않기 때문에, 원소가 아무리 많은 경우에도 성능이 눈에 띄게 좋아집니다!
위 경우는 컬렉션만 만들지 않을 뿐 수행하는 횟수는 같습니다.
아래의 예를 하나 더 들어보겠습니다.
리스트의 값을 꺼내 2배 한 뒤, 그 값이 3으로 나눠 떨어지는 첫 번째 값을 찾고자 합니다.
시퀀스를 사용하지 않는다면, 100부터 10000000까지 2배를 한 컬렉션을 먼저 생성하고,
다시 그 값을 하나씩 꺼내 3의 배수인 값으로 컬렉션을 생성한 뒤, 제일 첫번째 값을 꺼내옵니다.
시퀀스를 사용하게 되면 6번 수행만에 원하는 결과를 가져올 수 있습니다.
(100..10000000).asSequence()
.map{ println("map: $it"); it*2}
.filter{ println("filter: $it"); it % 3 == 0}
.first()
// map: 100
// filter: 200
// map: 101
// filter: 202
// map: 102
// filter: 204
generateSequence()
이 함수는 인자를 2개 받는데, seed 인수롤 초기값으로 받고 다음 인자로 next function인 람다함수로 파라미터를 받아 sequence list를 생성해서 리턴하게 됩니다.
val numbers = generateSequence(0) { it + 1 }
val numbersTo100 = numbers.takeWhile { it <= 100 }
println(numbersTo100.sum()) //모든 연산은 "sum()"이 호출될 때 수행된다. (최종 연산)
'Kotlin' 카테고리의 다른 글
inline 함수 (0) | 2022.04.01 |
---|---|
enum class, sealed class (0) | 2022.03.31 |
collection (0) | 2022.03.27 |
reduce, fold (0) | 2022.03.26 |
lateinit, lazy (0) | 2022.03.26 |