Sequences: Implementation of the filter

Let’s try to understand the code of the filter decorator. It contains a significant amount of code, so let’s break it down into parts. The decorator takes two parameters as input: sequence, from which it obtains the original iterator, and predicate, which defines the filtering condition (our lambda).

internal class FilteringSequence<T>(
    private val sequence: Sequence<T>,
    private val sendWhen: Boolean = true,
    private val predicate: (T) -> Boolean
) : Sequence<T> {

    override fun iterator(): Iterator<T> = object : Iterator<T> {
        val iterator = sequence.iterator()
        var nextState: Int = -1 // -1 for unknown, 0 for done, 1 for continue
        var nextItem: T? = null

The essence lies in the implementation of the hasNext() method. When this method is called, the decorator invokes the internal calcNext() function, which calculates the next element. Essentially, it iterates forward through the original iterator and looks for the first element that satisfies the condition defined in the predicate (our lambda). If it finds the next element that passes the filter, it is stored in the nextItem variable.

Read More