How to endlessly repeat the sequence in Kotlin?

I want to endlessly repeat T elements in Sequence<T> . This cannot be done using kotlin.collections.asSequence . For instance:

 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 the existence of some function kotlin.collections.repeat , but it does not exist, so I implemented it myself (for example, for this IntArray ):

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

This is very important, so I believe that there should be a more functional and less accurate way. If it exists, then what are / are the standard Kotlin methods (methods) for repeating collections (arrays a (n) (in) a finite number of times?

+9
source share
5 answers

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


If you allow coroutines, you can do this in a fairly clean way using sequence :

infinite number of times

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

Note the use of the qualified this expression this@repeat - just using this will access the lambda receiver, 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] 

final number of times

 fun <T> Sequence<T>.repeat(n: Int) = sequence { repeat(n) { yieldAll( this@repeat ) } } 
+9
source

To avoid using 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 several times, just take before smoothing:

 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 IntArray question, you IntArray first convert the array to Iterable<Int> (otherwise flatten() not 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" 

In addition, other types of Array , for example. ByteArray or LongArray , as well as Map not Iterable , but they all implement the asIterable() method, for example IntArray in the example above.

+4
source

I think this is pretty clear:

 generateSequence(0) { (it + 1) % intArray.size } .map { intArray[it] } .forEach { println(it) } 
+1
source

A general solution would be to reuse the sentence from this with extension functions:

 fun <T> Array<T>.asRepeatedSequence() = generateSequence(0) { (it + 1) % this.size }.map(::get) fun <T> List<T>.asRepeatedSequence() = generateSequence(0) { (it + 1) % this.size }.map(::get) 

Called as follows:

 intArray.asRepeatedSequence().forEach(::println) 
+1
source

I'm not sure if this is due to Kotlin API changes, but it is possible to do the following:

 fun <T> Sequence<T>.repeatForever() = generateSequence(this) { it }.flatten() 

Live example: https://pl.kotl.in/W-h1dnCFx

0
source

Source: https://habr.com/ru/post/1274368/


All Articles