如何在Kotlin中无限重复序列?

时间:2017-12-28 12:12:19

标签: collections kotlin sequence

我想在T中无限重复Sequence<T>个元素。这不能使用kotlin.collections.asSequence完成。例如:

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

这不是我想要的。我期望某种kotlin.collections.repeat函数存在,但是没有,所以我自己实现了一个(例如对于IntArray):

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

这是非常必要的,所以我觉得必须有一个更实用,更简洁的方法来做到这一点。如果它存在,那么Kotlin的标准方法是重复收集/数组a(n)(in)有限的次数?

5 个答案:

答案 0 :(得分:9)

更新:从Kotlin 1.3开始,协同程序不再具有实验性!尽可能多地使用它们:)

如果您允许使用coroutines,则可以使用sequence以非常干净的方式执行此操作:

  

无限次

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

注意使用qualified this expression this@repeat - 只需使用this即可引用lambda的接收器SequenceScope

然后你可以做

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]
  

有限的次数

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

答案 1 :(得分:4)

为避免使用实验协同程序,请使用:

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"

或者,如果您想多次重复整个集合,只需在展平前进行:

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"

对于原始问题IntArray,首先必须将数组转换为Iterable<Int>(否则flatten()不可用):

val intArray = intArrayOf(1, 2, 3)

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

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

此外,其他类型的Array,例如ByteArrayLongArray以及Map不是Iterable,但它们都在上面的示例中实现asIterable()方法,如IntArray

答案 2 :(得分:1)

我认为这很清楚:

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

答案 3 :(得分:1)

通用解决方案是重用此answer中包含扩展功能的提案:

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)

这样称呼:

intArray.asRepeatedSequence().forEach(::println)

答案 4 :(得分:0)

我不确定这是否是由于Kotlin中的API更改引起的,但是可以执行以下操作:

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

实时示例:https://pl.kotl.in/W-h1dnCFx