Evaluated Fully per Operation

Example code

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import gt.sandbox.util.output.impl.OutSettings
import kotlinx.coroutines.*

val out = Out.standard(OutSettings(printCoroutineName = false))

fun main() = runBlocking {
  listOf(1, 2, 3)
    .filter { out.printBlue("F$it, "); it % 2 == 1 }
    .map { out.printGreen("M$it, "); it * 2 }
    .forEach { out.print("E$it, ") }
}

Command to reproduce:

gt.sandbox.checkout.commit 310960e2f1eca158625e \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

F1, F2, F3, M1, M3, E2, E6, 
Sequences do minimal number of operations, while Iterables do full evaluated per each operation step.

Often we do not need to process a whole collection at every step to produce the result. Let’s say that we have a collection with millions of elements and, after processing, we only need to take the first 10. Why process all the other elements? Iterable processing doesn’t have the concept of intermediate operations, so a processed collection is returned from every operation. Sequences do not need that, therefore they can do the minimal number of operations required to get the result. - Effective Kotlin

Code example: where with Sequence we process less functions

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import gt.sandbox.util.output.impl.OutSettings

val out = Out.standard(OutSettings(printCoroutineName = false))

fun <T> T.printlnGreen() {
  out.printGreen(this.toString())
  println()
}

fun main(args: Array<String>) {

  println("As list - finding a match:")

  (1..10)
    .filter { out.printBlue("F$it, "); it % 2 == 1 }
    .map { print("M$it, "); it * 2 }
    .find { it > 5 }
    .printlnGreen()

  println()
  println()
  println("As sequence - finding a match:")
  (1..10).asSequence()
    .filter { out.printBlue("F$it, "); it % 2 == 1 }
    .map { print("M$it, "); it * 2 }
    .find { it > 5 }
    .printlnGreen()
}

Command to reproduce:

gt.sandbox.checkout.commit 318c2014d368df941520 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

6 is the match is the first match in this case:

As list - finding a match:
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, M1, M3, M5, M7, M9, 6


As sequence - finding a match:
F1, M1, F2, F3, M3, 6

For this reason, when we have some intermediate processing steps and our terminal operation does not necessarily need to iterate over all elements, using a sequence will most likely be better for your processing performance and it looks nearly the same. Examples of operations that do not necessarily need to process all the elements are [first, find, take, any, all, none, or indexOf].

Note


Backlinks