2015-08-14 81 views
2

作为一名Scala初学者,我仍在努力处理不可变列表。我正在尝试添加元素到我的列表中。这是我想要做的一个例子。Scala迭代构建列表

val list = Seq()::Nil 
val listOfInts = List(1,2,3) 
listOfInts.foreach {case x=> 
list::List(x) 
} 

期待,我会落得一个列表的列表:表(表(1),表(2),表(3))

从Java产品,我以前只是使用list.add(new ArrayList(i))来获得相同的结果。我在这里?

+1

的也许不是downvoting,SO应该有一个选项标记, “没走Coursera。” –

+0

'foreach'的返回类型是'Unit',所以你不会结束任何事情。你可能想要'地图'? –

回答

-2

你说在你的问题中,列表是不可变的,所以你都知道你不能改变它! Scala列表上的所有操作都将返回一个新的列表。顺便说一下,即使在Java中使用foreach来填充集合也被认为是不好的做法。斯卡拉成语为您的使用情况是:

list ::: listOfInts 

更短,更清晰,功能更强大,更地道,更容易推理(易变性使事情变得更加“复杂”尤其是写作lambda表达式的时候,因为它打破了语义一个纯粹的功能)。没有很好的理由给你一个不同的答案。

如果您想要可变性,可能出于性能考虑,请使用可变集合,如ArrayBuffer

1

由于List不可变您不能修改List

要从列表中构建列表中的1个项目列表,您可以在列表上列出mapforEachmap之间的差别在于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

在文档页面上有一些教程。

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或一个局部变量和返回你建立集合的选择。

在功能的世界里,你经常通过预先生成并反向:

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)) 
+0

正确的答案,因为它的工作原理,不好的答案,因为它显示了一个不好的做法和反模式 – Dici

+1

对不起,@Dici,但是每个想要构建集合的函数都可以选择是否使用可变构建器或者使用不可变单一收集。这是一次又一次的驱动,所以我再做一次。问题是如何构建它们,而不是如何使用地图等。 –

+0

那么你的代码片段比惯用的'xs :::(1到10)'有什么优势? – Dici

1

下面是副本,并将其添加打印语句从斯卡拉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()))到List(1)的开头。这就是打印出List(List(List()),1)的原因。

由于您的列表和listOfInts都是不可变的,所以您无法更改它们。你所能做的就是对它们执行一些操作,然后返回一个新的列表。在您的情况列表::列表(x)在循环内实际上不会做任何你可以看到,除非你打印出来。

0

斯卡拉你有(三级,如@ SOM-snytt显示)选项 - 选择可变集合(如缓冲液):

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) 
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

1

您可以简单地将此列表映射到列表的列表。 它保持不变性和功能的方法。

scala> List(1,2,3).map(List(_)) 
res0: List[List[Int]] = List(List(1), List(2), List(3)) 

或者你也可以使用尾递归:

@annotation.tailrec 
def f(l:List[Int],res:List[List[Int]]=Nil) :List[List[Int]] = { 
    if(l.isEmpty) res else f(l.tail,res :+ List(l.head)) 
} 

scala> f(List(1,2,3)) 
res1: List[List[Int]] = List(List(1), List(2), List(3)) 
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