foldLeft中的padTo错误

时间:2013-03-12 20:26:18

标签: scala

我正在学习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知识自行解决这个问题。

3 个答案:

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

应该引用泛型类型签名,以便始终返回正确的类型。