如何修改Kotlin序列的前缀但保留尾部?

时间:2016-01-31 14:05:06

标签: iterator sequence kotlin tail

Kotlin提供了taketakeWhile方法,让人们可以获取n的第一个Sequence<T>项,并将它们作为另一个序列单独处理,例如{{1}其中一些,drop与其他值等。

但是当我使用maptake时,序列的尾部就会被删除。

现在,给定一个一次约束的序列,如何将其任意前缀转换为保留尾部的另一个序列(如果它仍然存在)?

示例:

takeWhile

如何为多个前缀执行相同操作?

示例:

val seq = (1..10).asSequence().constrainOnce() 
// emits 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

val modified = seq.changePrefix { take(5).map { -1 * it } }
// emits -1, -2, -3, -4, -5, 6, 7, 8, 9, 10

注意:问题是有意提出的answered by the author

1 个答案:

答案 0 :(得分:3)

如果val seq = (1..10).asSequence().constrainOnce() val modified = seq.changePrefixes( { take(3).map { it * -1 } }, { drop(1).take(3).map { it * 100 } }, { map { 0 } } ) //emits -1, -2, -3, 500, 600, 700, 0, 0, 0 曾被约束,则意味着不允许从中创建多个Sequence<T>。因此,解决方案是创建一个迭代器并从中生成更改的前缀和剩余的尾部。

Iterator的{​​{3}}方法在这里证明是有用的,因为它创建了一个由迭代器支持的序列。剩下的只是连接序列。

以下是您如何进行一项更改:

Iterator<T>

请注意,两个序列是从同一个迭代器创建的,但它可以,因为

  • val seq = (1..10).asSequence().constrainOnce() val modified = seq.iterator().let { iter -> iter.asSequence().take(5).map { it * -1 } + iter.asSequence() } 被懒惰地评估
  • 这两个序列一起使用,不会泄漏
  • 连接中的第二个序列的评估将在第一个序列完成后开始

以下是如何将其推广到任意数量的序列运算符:

Sequence

fun <T> Sequence<T>.changePrefixes(vararg operators: Sequence<T>.() -> Sequence<T>) : Sequence<T> { val i = iterator() return operators.fold(emptySequence<T>()) { acc, it -> acc + i.asSequence().it() } + i.asSequence() } 生成由fold从迭代器operators支持的序列提供的连锁序列链,然后将未修改的尾部附加到i结果。

此实施的限制是,当运营商包含fold时,被拒绝的项目将被删除,并且不会被发送到下一个序列。