Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin sequence concatenation

Tags:

kotlin

val seq1 = sequenceOf(1, 2, 3)
val seq2 = sequenceOf(5, 6, 7)
sequenceOf(seq1, seq2).flatten().forEach { ... }

That's how I'm doing sequence concatenation but I'm worrying that it's actually copying elements, whereas all I need is an iterator that uses elements from the iterables (seq1, seq2) I gave it.

Is there such a function?

like image 627
Yuri Geinish Avatar asked Oct 20 '16 18:10

Yuri Geinish


2 Answers

Your code doesn't copy the sequence elements, and sequenceOf(seq1, seq2).flatten() actually does what you want: it generates a sequence that takes items first from seq1 and then, when seq1 finishes, from seq2.

Also, operator + is implemented in exactly this way, so you can just use it:

(seq1 + seq2).forEach { ... }

The source of the operator is as expected:

public operator fun <T> Sequence<T>.plus(elements: Sequence<T>): Sequence<T> {
    return sequenceOf(this, elements).flatten()
}

You can take a look at the implementation of .flatten() in stdlib that uses FlatteningSequence, which actually switches over the original sequences' iterators. The implementation can change over time, but Sequence is intended to be as lazy as possible, so you can expect it to behave in a similar way.

Example:

val a = generateSequence(0) { it + 1 }
val b = sequenceOf(1, 2, 3)

(a + b).take(3).forEach { println(it) }

Here, copying the first sequence can never succeed since it's infinite, and iterating over (a + b) takes items one by one from a.


Note, however, that .flatten() is implemented in a different way for Iterable, and it does copy the elements. Find more about the differences between Iterable and Sequence here.

like image 142
hotkey Avatar answered Oct 20 '22 20:10

hotkey


Something else you might need to do is create a sequence of sequences:

    val xs = sequence {
        yield(1)
        yield(2)
    }

    val twoXs = sequence {
        yieldAll(xs)
        // ... interesting things here ... 
        yieldAll(xs)
    }

This doesn't do anything that xs + xs doesn't do, but it gives you a place to do more complex things.

like image 41
James Moore Avatar answered Oct 20 '22 20:10

James Moore