Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I infinitely repeat a sequence in Kotlin?

I want to infinitely repeat T elements in a Sequence<T>. This can't be done using kotlin.collections.asSequence. For example:

val intArray = intArrayOf(1, 2, 3)
val finiteIntSequence = intArray.asSequence()
val many = 10
finiteIntSequence.take(many).forEach(::print)
// 123

This is not what I want. I expected some kind of kotlin.collections.repeat function to exist, but there isn't, so I implemented one myself (e.g. for this IntArray):

var i = 0
val infiniteIntSequence = generateSequence { intArray[i++ % intArray.size] }
infiniteIntSequence.take(many).forEach(::print)
// 1231231231

This is quite imperative, so I feel there must be a more functional and less verbose way to do this. If it exists, what is/are Kotlin's standard way(s) to repeat collections / arrays a(n) (in)finite amount of times?

like image 812
Erik Avatar asked Dec 28 '17 12:12

Erik


People also ask

How do you repeat on Kotlin?

Example 1 – Kotlin repeat() In this example, we will use a repeat statement to execute print statement 4 times. fun main(args: Array) { repeat(4) { println("Hello World!") } }

How do I create a sequence on Kotlin?

From a function One more way to create a sequence is by building it with a function that calculates its elements. To build a sequence based on a function, call generateSequence() with this function as an argument. Optionally, you can specify the first element as an explicit value or a result of a function call.

What is the key difference between iterable T and sequence T in Kotlin?

The key difference lies in the semantics and the implementation of the stdlib extension functions for Iterable<T> and Sequence<T> . For Sequence<T> , the extension functions perform lazily where possible, similarly to Java Streams intermediate operations. For example, Sequence<T>.


3 Answers

Update: coroutines are no longer experimental as of Kotlin 1.3! Use them as much as you like :)


If you allow the use of coroutines you can do this in a pretty clean way using sequence:

an infinite amount of times

fun <T> Sequence<T>.repeat() = sequence { while (true) yieldAll(this@repeat) }

Note the use of a qualified this expression this@repeat - simply using this would refer to the lambda's receiver, a SequenceScope.

then you can do

val intArray = intArrayOf(1, 2, 3)
val finiteIntSequence = intArray.asSequence()
val infiniteIntSequence = finiteIntSequence.repeat()

println(infiniteIntSequence.take(10).toList())
// ^ [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]

a finite amount of times

fun <T> Sequence<T>.repeat(n: Int) = sequence { repeat(n) { yieldAll(this@repeat) } }
like image 185
Salem Avatar answered Oct 20 '22 12:10

Salem


To avoid using the experimental coroutines, use:

generateSequence { setOf("foo", 'b', 'a', 'r') }
  .flatten() // Put the Iterables' contents into one Sequence
  .take(5) // Take 5 elements
  .joinToString(", ")

// Result: "foo, b, a, r, foo"

or alternatively, if you want to repeat the entire collection a number of times, just take before flattening:

generateSequence { setOf("foo", 'b', 'a', 'r') }
  .take(5) // Take the entire Iterable 5 times
  .flatten() // Put the Iterables' contents into one Sequence
  .joinToString(", ")

// Result: "foo, b, a, r, foo, b, a, r, foo, b, a, r, foo, b, a, r, foo, b, a, r"

For the original question's IntArray, the array first must be converted to an Iterable<Int> (otherwise flatten() isn't available):

val intArray = intArrayOf(1, 2, 3)

generateSequence { intArray.asIterable() }
  .flatten()
  .take(10)
  .joinToString(", ")

// Result: "1, 2, 3, 1, 2, 3, 1, 2, 3, 1"

Furthermore, other types of Array, e.g. ByteArray or LongArray, as well as Map are not Iterable, but they all implement the asIterable() method like IntArray in the example above.

like image 6
Erik Avatar answered Oct 20 '22 12:10

Erik


I think this is pretty clear:

generateSequence(0) { (it + 1) % intArray.size }
        .map { intArray[it] }
        .forEach { println(it) }
like image 3
s1m0nw1 Avatar answered Oct 20 '22 14:10

s1m0nw1