2013-03-12 33 views
2

我在學習自己斯卡拉和我寫的一個小測試應用程序不是我所期望的方式工作。有人可以幫助我理解我的測試應用程序失敗的原因。padTo錯誤裏面foldLeft

我的小的測試應用程序由一個執行以下操作「減壓」

val testList = List(Tuple2(4, 'a'), Tuple2(1, 'b'), Tuple2(2, 'c'), Tuple2(2, 'a'), Tuple2(1, 'd'), Tuple2(4, 'e')) 
    require(decompress(testList) == List('a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e')) 

換言之,Tuple2對象應該只被「解壓縮」到一個更詳細的形式的「解壓縮」的方法。然而,我從這個方法中得到的所有東西都是List('a','a','a','a') - padTo語句適用於第一個Tuple2,但它只是突然停止工作?如果我然而使用for循環做每個元素的填充 - 一切正常......?

的完整代碼:

object P12 extends App { 

    def decompress(tList: List[Tuple2[Int,Any]]): List[Any] = { 
    val startingList: List[Any] = List(); 
    val newList = tList.foldLeft(startingList)((b,a) => { 
     val padCount = a._1; 
     val padElement = a._2; 

     println 
     println(" Current list: " + b) 
     println(" Current padCount: " + padCount) 
     println(" Current padElement: " + padElement) 
     println(" Padded using padTo: " + b.padTo(padCount, padElement)) 
     println 

     // This doesn't work 
     b.padTo(padCount, padElement) 

//  // This works, yay 
//  var tmpNewList = b; 
//  for (i <- 1 to padCount) 
//  tmpNewList = tmpNewList :+ padElement 
//  tmpNewList 
    }) 
    newList 
    } 

    val testList = List(Tuple2(4, 'a'), Tuple2(1, 'b'), Tuple2(2, 'c'), Tuple2(2, 'a'), Tuple2(1, 'd'), Tuple2(4, 'e')) 
    require(decompress(testList) == List('a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e')) 
    println("Everything is okay!") 
} 

任何幫助表示讚賞 - 學習Scala,只是想不通我自己這個問題,我目前的知識斯卡拉。

回答

1

的問題是,padTo實際填寫列表直到達到給定大小。所以第一次它的工作原理與4個元素填充,但下一次你就必須添加CURENT列表的實際長度 - 因此:

def decompress(tList: List[Tuple2[Int,Any]]): List[Any] = { 
    val newList = tList.foldLeft(List[Any]())((b,a) => { 
    b.padTo(a._1+b.length, a._2) 
}) 
newList 
} 
+0

謝謝,讚賞:) – 2013-03-13 06:39:39

0

這工作:

scala> testList.foldLeft(List[Char]()){ case (xs, (count, elem)) => xs ++ List(elem).padTo(count, elem)} 
res7: List[Char] = List(a, a, a, a, b, c, c, a, a, d, e, e, e, e) 

這個問題實際上是,當你說b.padTo(padCount, padElement)你總是使用相同的列表(b)填滿的元素。由於第一個元組數據生成的元素最多,因此在下一步foldLeft中沒有添加任何元素。如果你改變了第二元組數據,你會看到一個變化:

scala> val testList = List(Tuple2(3, 'a'), Tuple2(4, 'b')) 
testList: List[(Int, Char)] = List((3,a), (4,b)) 

scala> testList.foldLeft(List[Char]()){ case (xs, (count, elem)) => xs.padTo(count, elem)} 
res11: List[Char] = List(a, a, a, b) 

相反的foldLeft你也可以使用flatMap生成的元素:

scala> testList flatMap { case (count, elem) => List(elem).padTo(count, elem) } 
res8: List[Char] = List(a, a, a, a, b, c, c, a, a, d, e, e, e, e) 

順便說一句,Tuple(3, 'a')可以寫(3, 'a')3 -> 'a'

請注意,padTo不能按預期方式工作,當您的數據計數爲< = 0時:

scala> List(0 -> 'a') flatMap { case (count, elem) => List(elem).padTo(count, elem) } 
res31: List[Char] = List(a) 

因此使用由閣樓霍爾提到的解決方案:

def decompress[A](xs: Seq[(Int, A)]) = 
    xs flatMap { case (count, elem) => Seq.fill(count)(elem) } 

scala> decompress(List(2 -> 'a', 3 -> 'b', 2 -> 'c', 0 -> 'd')) 
res34: Seq[Char] = List(a, a, b, b, b, c, c) 

scala> decompress(List(2 -> 0, 3 -> 1, 2 -> 2)) 
res35: Seq[Int] = List(0, 0, 1, 1, 1, 2, 2) 

使用泛型類型簽名應以始終返回正確的類型被稱爲。

1

你可以做你的解壓縮這樣的:

val list = List(Tuple2(4, 'a'), Tuple2(1, 'b'), Tuple2(2, 'c'), Tuple2(2, 'a'), Tuple2(1, 'd'), Tuple2(4, 'e')) 
list.flatMap{case (times, value) => Seq.fill(times)(value)} 
+0

與之相似, '高清解壓(TSEQ:序號[Tuple2 [Int,Any]]):Seq [Any] = tSeq.flatMap {e => Seq.fill(e._1)(e._2)}' 即使用不同的flatMap語法,但我也重構瞭解決方案使用Seq,因爲我看到它的集合類層次結構更高 - 我猜會支持不可變和可變集合類型(List是一個不可變的集合類型實現)。 – 2013-03-13 07:15:25