我正在学习Scala,我写的一个小测试应用程序并没有像我期望的那样工作。有人可以帮我理解为什么我的测试应用程序失败了。
我的小测试应用程序包含一个“解压缩”方法,它执行以下“解压缩”
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,只是无法凭借我目前的Scala知识自行解决这个问题。
答案 0 :(得分: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)}
答案 1 :(得分: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
}
答案 2 :(得分: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'
请注意,如果数据的计数为&lt; = 0,padTo
将无法正常工作:
scala> List(0 -> 'a') flatMap { case (count, elem) => List(elem).padTo(count, elem) }
res31: List[Char] = List(a)
因此使用Garret Hall提到的解决方案:
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)
应该引用泛型类型签名,以便始终返回正确的类型。