2

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

4

3 回答 3

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)}
于 2013-03-12T20:36:25.027 回答
1

问题是 padTo 实际上将列表填充到给定大小。所以第一次它使用填充的 4 个元素,但下一次你必须添加当前列表的实际长度 - 因此:

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
}
于 2013-03-12T20:43:51.853 回答
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)

因此使用 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)

应参考使用泛型类型签名,以便始终返回正确的类型。

于 2013-03-12T20:36:00.707 回答