As a Scala beginner I am still struggling working with immutable lists. All I am trying to do append elements to my list. Here's an example of what I am trying to do.
val list = Seq()::Nil
val listOfInts = List(1,2,3)
listOfInts.foreach {case x=>
list::List(x)
}
expecting that I would end up with a list of lists: List(List(1),List(2),List(3))
Coming from java I am used to just using list.add(new ArrayList(i)) to get the same result. Am I way off here?
答案 0 :(得分:1)
由于List
不可变,您无法修改List
。
要从列表中构建1个项目列表的列表,您可以在列表上map
。 forEach
和map
之间的区别在于forEach
不返回任何内容,即Unit
,而map
从某些函数的返回返回List。
scala> def makeSingleList(j:Int):List[Int] = List(j)
makeSingleList: (j: Int)List[Int]
scala> listOfInts.map(makeSingleList)
res1: List[List[Int]] = List(List(1), List(2), List(3))
答案 1 :(得分:1)
文档页面上有教程。
ListBuffer有一个模糊,如果你这样摆动。
否则,
scala> var xs = List.empty[List[Int]]
xs: List[List[Int]] = List()
scala> (1 to 10) foreach (i => xs = xs :+ List(i))
scala> xs
res9: List[List[Int]] = List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))
您可以选择使用像ListBuffer
这样的可变构建器或本地var,并返回您构建的集合。
在功能性世界中,您经常通过预先构建然后反转来构建:
scala> var xs = List.empty[List[Int]]
xs: List[List[Int]] = List()
scala> (1 to 10) foreach (i => xs = List(i) :: xs)
scala> xs.reverse
res11: List[List[Int]] = List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))
答案 2 :(得分:1)
下面是使用添加的print语句从Scala REPL进行复制和粘贴以查看发生的情况:
scala> val list = Seq()::Nil
list: List[Seq[Nothing]] = List(List())
scala> val listOfInts = List(1,2,3)
listOfInts: List[Int] = List(1, 2, 3)
scala> listOfInts.foreach { case x=>
| println(list::List(x))
| }
List(List(List()), 1)
List(List(List()), 2)
List(List(List()), 3)
在foreach循环的第一次迭代中,您实际上是在获取listOfInts的第一个元素(即1),将其放入新列表(List(1)),然后添加新元素列表(列表(List()))到List(1)的开头。这就是它打印出List(List(List()),1)。
的原因由于您的list和listOfInts都是不可变的,因此您无法更改它们。您所能做的就是对它们执行某些操作,然后返回包含更改的新列表。在你的案例列表中:循环内部的List(x)实际上并没有做任何你能看到的事情,除非你打印出来。
答案 3 :(得分:1)
鉴于 val listOfInts = List(1,2,3)
,您希望最终结果为 List(List(1),List(2),List(3))
。
我能想到的另一个好方法是滑动(通过在它们上面传递“滑动窗口”来组合固定大小块中的元素)
scala> val listOfInts = List(1,2,3)
listOfInts: List[Int] = List(1, 2, 3)
scala> listOfInts.sliding(1)
res6: Iterator[List[Int]] = non-empty iterator
scala> listOfInts.sliding(1).toList
res7: List[List[Int]] = List(List(1), List(2), List(3))
// If pass 2 in sliding, it will be like
scala> listOfInts.sliding(2).toList
res8: List[List[Int]] = List(List(1, 2), List(2, 3))
有关滑动的更多信息,您可以在 scala.collection.IterableLike 中阅读滑动。
答案 4 :(得分:0)
在scala中你有两个(三个,如@som-snytt所示)选项 - 选择一个可变集合(如Buffer):
scala> val xs = collection.mutable.Buffer(1)
// xs: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1)
scala> xs += 2
// res10: xs.type = ArrayBuffer(1, 2)
scala> xs += 3
// res11: xs.type = ArrayBuffer(1, 2, 3)
正如您所看到的,它就像您在Java中使用列表一样工作。您拥有的另一个选项,实际上是非常鼓励的,是选择在功能上处理列表,就是这样,您需要一些功能并将其应用于集合的每个元素:
scala> val ys = List(1,2,3,4).map(x => x + 1)
// ys: List[Int] = List(2, 3, 4, 5)
scala> def isEven(x: Int) = x % 2 == 0
// isEven: (x: Int)Boolean
scala> val zs = List(1,2,3,4).map(x => x * 10).filter(isEven)
// zs: List[Int] = List(10, 20, 30, 40)
答案 5 :(得分:0)
// input: List(1,2,3)
// expected output: List(List(1), List(2), List(3))
val myList: List[Int] = List(1,2,3)
val currentResult = List()
def buildIteratively(input: List[Int], currentOutput: List[List[Int]]): List[List[Int]] = input match {
case Nil => currentOutput
case x::xs => buildIteratively(xs, List(x) :: currentOutput)
}
val result = buildIteratively(myList, currentResult).reverse
答案 6 :(得分:-2)
你在问题中说该列表是不可变的,所以你做意识到你不能改变它! Scala列表上的所有操作都会返回新列表。顺便说一句,即使在Java中使用foreach
来填充集合也被认为是一种不好的做法。用例的Scala成语是:
list ::: listOfInts
更短,更清晰,更实用,更具惯用性和更容易推理(可变性使事情更多"复杂"特别是在编写lambda表达式时,因为它打破了纯函数的语义)。没有充分的理由给你一个不同的答案。
如果您想要可变性(可能出于性能目的),请使用可变集合,例如ArrayBuffer
。