Kotlin-确保在开始下一个收集操作之前完成收集操作

时间:2019-07-29 16:50:29

标签: kotlin collections sequence

如果编写以下代码:

fun main(args: Array<String>) {
    val letters = listOf("a", "b", "c", "d")
    letters.map { print(it); it }.forEach { print(it) }
}

我得到以下输出:abcdabcd

但是,如果我改为将其更改为序列:

fun main(args: Array<String>) {
    val letters = listOf("a", "b", "c", "d")
    letters.asSequence().map { print(it); it }.forEach { print(it) }
}

我得到以下信息:aabbccdd

似乎Kotlin的序列不能保证“组操作”(例如mapforEach)将在另一个开始之前完成,但是当我们将这些操作应用于集合时,可以保证该操作将一次完成。

我们如何保证在开始执行下一个链接的“组操作”之前,将对集合或序列中的所有元素应用诸如mapforEach之类的“组操作” ?

1 个答案:

答案 0 :(得分:3)

  

我们如何保证在开始执行下一个链接的“组操作”之前,将诸如map或forEach之类的“组操作”应用于集合或序列中的所有元素?

行为取决于输入是Collection还是Sequence

  • 集合将对集合中的每个元素应用链中的单个操作,然后再应用链中的下一个操作。这就是为什么您一次看到"abcd",然后再次看到"abcd"的原因。
  • 在将所有操作应用于序列中的下一个元素之前,序列会将链中的每个操作应用于序列中的每个元素。这就是为什么您看到"aa",然后看到"bb"等的原因。

主要要了解的是Kotlin序列是 lazy 。每当您转换Sequence(例如通过map或其他函数)时,该转换也是 缓慢应用的。只有在您实际评估序列中的元素(在您的情况下,这是由forEach完成)时,转换才适用。

如果您需要Collection中的Sequence行为,则必须先将序列转换为集合。您可以调用sequence.toList()或对其进行转换,但是无法从Sequence中获得“渴望的”行为。


我们来看看两种不同的情况。

lettersList<String>

列表不是很懒。为了将一个map List转换为另一个map { print(it); it },我们必须遍历整个输入列表,转换每个元素并构建输出列表。考虑到这一点...

第一个操作"a", "b", "c", "d"从输入中读取每个值,然后打印并创建一个新列表。它返回一个包含"abcd"的列表,并且程序已打印forEach { print(it) }

第二个操作"abcd"遍历列表并打印每个元素。完成此操作后,程序将再次打印"abcdabcd",总输出为letters

Sequence<String>map

序列是惰性的。为了使Sequence一个TransformingSequence到另一个print(it); return it,该程序保留了转换方法,并等待直到别人实际上需要一个值,然后才能执行转换。所以...

第一个操作将创建一个新的TransformingSequence,它同时保留原始序列和print转换器。它返回这个新序列,程序尚未打印任何内容。

第二个操作是“终端”(即它实际上是评估序列中的每个元素)。遍历序列并打印每个元素。但是请记住:我们要遍历的序列是一个forEach,它本身会打印每个元素!因此,"aa"调用中的第一个"bb"动作将打印"aabbccdd",第二个动作将打印{{1}},依此类推,总输出为{{1}}。