元组的Scala列表在for循环后变为空

Scala List of tuple becomes empty after for loop

我有一个 Scala 元组列表“params”,大小为 28。我想遍历并打印列表中的每个元素,但是没有打印出任何内容。完成for循环后,我检查了列表的大小,现在变成了0。

我是 scala 的新手,在谷歌搜索了很长时间后我无法弄清楚。

val primes = List(11, 13, 17, 19, 2, 3, 5, 7)
val params = primes.combinations(2)
println(params.size)

for (param <- params) {
  print(param(0), param(1))
}
println(params.size)



List 中的

combinations 方法创建一个 Iterator。一旦使用 size 等方法消耗了 Iterator,它将是空的。

来自docs

one should never use an iterator after calling a method on it.

如果注释掉println(params.size),可以看到for循环打印出元素,但是最后的println(params.size)会保留为0。

primes.combinations(2) returns 迭代器。

Iterators are data structures that allow to iterate over a sequence of elements. They have a hasNext method for checking if there is a next element available, and a next method which returns the next element and discards it from the iterator.

所以,它就像指向 Iterable 集合的指针。完成迭代后,您将无法再进行迭代。

println(params.size) 执行时,计算 size 时迭代完成,现在参数指向结束。因此 for (param <- params) 将等效于围绕空集合循环。

有两种可能的解决方案:

  1. for循环前不检查大小
  2. 将迭代器转换为 Iterable,例如列表。 params = primes.combinations(2).toList

要了解有关 Iterator 和 Iterable 的更多信息,请参阅 What is the relation between Iterable and Iterator?

补充 Johny 的出色回答:

Do you know how I can save the result from combination methods to use for later?

好吧,正如已经建议的那样,您可以 toList
但是,请注意 combinations returns 和 Iterator 是有原因的,这是因为数据可能太大,如果您不介意,那就继续吧;但你还是可以利用懒惰。

例如,让我们在收集结果之前将内部列表转换为元组:

val params =
  primes
    .combinations(2)
    .collect {
      case a :: b :: Nil => (a, b)
    }.toList

以同样的方式,在执行 toList
之前,您可以像另一个 mapfilter 一样在链中添加额外的步骤 更好的是,如果您的最终操作类似于 foreach(foo),那么您甚至不需要将所有内容都收集到 List