Sequences vs Collections in Kotlin
Learn the key differences between Sequences and Collections in Kotlin to optimize your code performance. This article compares their characteristics, demonstrates performance differences with practical examples, and shows when to use each approach. Collections create new instances after transformations while Sequences operate lazily, offering significant performance benefits for large data sets with multiple transformations.
Introduction
Do you often work on large collections with tons of transformations required? You have to know how to improve the performance.
Collections
- New collection is created after each transformation
- Good for small list with low amount of transformations needed
- Transformations are executed on whole collection
- Non-Lazy
Sequences
- Creates TransformingSequence instead of new collections
- Good for large list with a lot of transformations needed
- Transformations are executed on each element
- Lazy
Performance
Code
The task: Cleanup those urls. Remove protocol, not needed characters. Remember that's just example.
For test purposes we will multiply initial list
val urls = listOf(
"https://www.example.com/?battle=authority",
"https://example.com/?achiever=bubble#amusement",
"http://actor.example.net/?blow=amusement&afterthought=adjustment",
"http://www.example.net/box/badge?beef=bottle#bag",
"http://example.com/",
"https://www.example.com/blow#balance",
"http://brake.example.com/box.aspx",
"https://www.example.com/base",
"https://example.net/belief",
"http://www.example.com/",
"http://www.example.com/",
"https://breath.example.com/afterthought.htm?bit=balance",
"https://example.net/bite/believe",
"http://www.example.com/#bird",
"http://example.com/behavior/basin.html?airport=berry&bedroom=acoustics",
"https://www.example.net/",
"https://www.example.com/books?bead=ants",
"http://www.example.com/",
"http://www.example.com/anger",
"http://beginner.example.com/birds?account=badge&amusement=bike#birds"
)
val manyUrls = urls * 100
println("Urls ${manyUrls.count()}")
val (nonSequenceList, nonSequenceTime) = measureTimedValue {
manyUrls
.filter { it.contains("example.com") }
.map { it.removePrefix("https://") }
.map { it.removePrefix("http://") }
.map { it.removePrefix("www.") }
.map { it.removeSuffix("/") }
.map { "$it/random_path" }
}
val (sequenceList, sequenceTime) = measureTimedValue {
manyUrls
.asSequence()
.filter { it.contains("example.com") }
.map { it.removePrefix("https://") }
.map { it.removePrefix("http://") }
.map { it.removePrefix("www.") }
.map { it.removeSuffix("/") }
.map { "$it/random_path" }
.toList()
}
println("Count Sequence ${sequenceList.count()} vs Collection ${nonSequenceList.count()}")
println("Time Sequence $sequenceTime vs Collection $nonSequenceTime")
}
Remember to import needed resources
@file:OptIn(ExperimentalTime::class)
import kotlin.time.ExperimentalTime
import kotlin.time.measureTimedValue
Performance tests
6 transformations
.filter { it.contains("example.com") }
.map { it.removePrefix("https://") }
.map { it.removePrefix("http://") }
.map { it.removePrefix("www.") }
.map { it.removeSuffix("/") }
.map { "$it/random_path" }
20 urls & 6 transformations
Run | Sequence | Collection |
---|---|---|
1 | 10.655706ms | 17.304207ms |
2 | 10.392919ms | 20.190484ms |
3 | 10.275253ms | 18.017698ms |
2k urls & 6 transformations
Run | Sequence | Collection |
---|---|---|
1 | 19.171929ms | 31.647107ms |
2 | 15.764996ms | 27.570382ms |
3 | 17.748853ms | 31.490926ms |
20k urls & 6 transformations
Run | Sequence | Collection |
---|---|---|
1 | 27.254874ms | 53.043007ms |
2 | 27.231176ms | 52.437605ms |
3 | 27.075628ms | 55.805330ms |
200k urls & 6 transformations
Run | Sequence | Collection |
---|---|---|
1 | 55.448596ms | 124.119595ms |
2 | 49.847435ms | 134.345523ms |
3 | 52.328476ms | 144.570364ms |
2kk urls & 6 transformations
Run | Sequence | Collection |
---|---|---|
1 | 420.379349ms | 759.274169ms |
2 | 368.751423ms | 689.146264ms |
3 | 373.576750ms | 691.970425ms |
1 transformation
.filter { it.contains("example.com") }
20 urls & 1 transformation
Run | Sequence | Collection |
---|---|---|
1 | 10.474949ms | 12.888582ms |
2 | 8.225425ms | 12.196659ms |
3 | 7.857158ms | 13.368340ms |
2k urls & 1 transformation
Run | Sequence | Collection |
---|---|---|
1 | 9.959861ms | 13.648944ms |
2 | 15.699487ms | 24.050235ms |
3 | 12.971994ms | 16.896744ms |
20k urls & 1 transformation
Run | Sequence | Collection |
---|---|---|
1 | 12.637821ms | 19.825526ms |
2 | 11.659926ms | 18.008385ms |
3 | 12.154623ms | 20.246985ms |
200k urls & 1 transformation
Run | Sequence | Collection |
---|---|---|
1 | 27.254874ms | 39.902933ms |
2 | 27.231176ms | 52.437605ms |
3 | 27.075628ms | 55.805330ms |
2kk urls & 1 transformation
Run | Sequence | Collection |
---|---|---|
1 | 145.232857ms | 85.404677ms |
2 | 140.731783ms | 83.639622ms |
3 | 142.480267ms | 89.809333ms |
Summary
You can have huge performance gain if you work with large sets of data. It also can reduce performance in some cases so use carefully.