如何修改Kotlin序列的前缀但保留尾部? [英] How to modify a prefix of a Kotlin sequence but retain the tail?

查看:177
本文介绍了如何修改Kotlin序列的前缀但保留尾部?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Kotlin提供获取 takeWhile 方法让人们先拿 n 序列< T> 的项目,并将它们作为另一个序列单独处理,例如 drop 其中一些,映射到其他值等。

Kotlin provides take and takeWhile methods which let one to take first n items of a Sequence<T> and process them separately as another sequence, for example, drop some of them, map to other values etc.

但当我使用时取 takeWhile ,序列的尾部被删除。

But when I use take and takeWhile, the tail of the sequence is dropped.

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

Now, given a once-constrained sequence, how do I transform its arbitrary prefix to another sequence retaining the tail if it remains?

示例:

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

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

How do I do the same for more than one prefix?

示例:

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

注意:问题是有意提出的,并且作者要求

推荐答案

序列< T> 一度受约束时,意味着不允许从中创建多个 Iterator 。因此,解决方案是创建一个迭代器并从中生成更改的前缀和剩余的尾部。

When a Sequence<T> is once-constrained, it means that it is not allowed to create more than one Iterator from it. Therefore the solution is to create one iterator and produce both the changed prefix and the remaining tail from it.

迭代器< T> asSequence() 方法在这里证明是有用的,因为它创建了一个由迭代器支持的序列。剩下的只是连接序列。

The Iterator<T>'s asSequence() method proves to be useful here as it creates a sequence backed by the iterator. What remains is just to concatenate the sequences.

以下是一次更改的方法:

Here's how you do it for one change:

val seq = (1..10).asSequence().constrainOnce()
val modified = seq.iterator().let { iter -> 
    iter.asSequence().take(5).map { it * -1 } + iter.asSequence()
}

请注意,两个序列是从同一个迭代器创建的,但没关系,因为

Note that two sequences are created from the same iterator, but it's OK because


  • 序列被懒惰地评估

  • 这两个序列一起使用而不会泄漏

  • 串联中第二个序列的评估将在第一个序列完成后开始

  • Sequences are evaluated lazily
  • The two sequences are used together and do not leak out
  • Evaluation of the second sequence in concatenation will start after the first one finishes

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

And here's how to generalize it to arbitrary number of sequence operators:

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 从迭代器支持的序列生成由运算符提供的串联序列链 i ,然后将未修改的尾部附加到 fold 结果。

This fold produces a chain of concatenated sequences provided by operators from the sequences backed by the iterator i, and then appends the unmodified tail to the fold result.

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

The limitation of this implementation is that when an operator includes takeWhille, the rejected item will be dropped and won't be emitted into the next sequence.

这篇关于如何修改Kotlin序列的前缀但保留尾部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆