使用不可变列表将项目附加到 for 循环中的列表?

Append items to a list in a for loop using an immutable list?

val list = List()
for(i <- 1 to 10){
    list:+i
}
println(list)

这最终给了我一个空列表,尽管它应该用 1 到 10 之间的数字填充?我有一个理论,由于“:”运算符,它每次都会创建一个新列表,但我不完全确定。我已经使用 ListBuffer 解决了这个问题,但我想学习如何使用不可变列表来解决这个问题。谢谢。

您不能向不可变列表添加元素(即改变列表)。 你说得对:

I have a theory that it creates a new list each time

作为第一步考虑

      var list = List.empty[Int]
      
      for(i <- 1 to 10) {
        list = list :+ i
      }

      println(list)

请注意,列表现在是 variable 以便我们可以重新分配值,但是 列表 仍然是一个不可变对象。事实上,对于每个迭代,我们将一个 new 列表重新分配给变量列表,并附加一个元素 如果你不喜欢使用变量你可以使用折叠操作,它与上面的for没有太大区别,它仍然构建部分列表逐个添加元素

      val result = (1 to 10).foldLeft(List.empty[Int]){ (partial_list, item) =>
        partial_list :+ item
      }
      
      println(result)

这里是:+的简化签名:

def :+(elem: B): List[B] 

它 returns 一个带有 elem 的新列表,因此它不会改变当前的 list

为了使这项工作切换到 ListBuffer 即可变的东西:


import scala.collection.mutable.ListBuffer


val buffer = ListBuffer.empty[Int]

for(i <- 1 to 10) {
  buffer += i
}

println(buffer)

如果你想保留不可变列表,你可以使用 fold:

进行累积
val list = List.empty[Int]

(1 to 10)
  .foldLeft(list) { (acc, value) =>  acc :+ value }

这个 class 问题没有单一的功能解决方案,但这里有一些选择。

对于问题中简单的情况,可以这样做

List.range(1,11) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

如果要根据索引为每个元素计算不同的值,请使用 tabulate:

List.tabulate(10)(x => x*3) // List(0, 3, 6, 9, 12, 15, 18, 21, 24, 27)

(如果逻辑比这个复杂可以传一个函数)

如果您正在构建列表但不确定是否需要每个元素,请使用 Option 然后 flatten:

def genValue(i: Int): Option[Int] = ???

List.tabulate(10)(genValue).flatten

这将丢弃 genValue returns None 的任何值,并提取 Int returns Some(???) 的值。

如果每个操作可能 return 不同数量的元素,使用 List 然后 flatten:

def genValue(i: Int): List[Int] = ???

List.tabulate(10)(genValue).flatten

这将从 genValue 编辑的所有 List 值 return 中获取所有元素,并将它们放入单个 List[Int].

如果事先不知道 List 的长度,那么最好的解决方案可能是递归函数。虽然一开始这似乎令人生畏,但值得学习如何使用它们,因为它们通常是解决问题的最简洁方法。