3

我正在尝试解决S-99 的问题 12:九十九个 Scala 问题

给定问题 P10 中指定的运行长度代码列表,构建其未压缩版本。例子:

scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)))
res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)

我试图对列表中的元素进行模式匹配,然后使用 for 循环连接 char,但在第 5 行出现以下编译错误:

type mismatch;  found   : scala.collection.immutable.IndexedSeq[List[A]]  required: List[A]

1 def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
2     case Nil => Nil
3     case x :: xs => {
4                    for {
5                       i <- 1 to x._1
6                    }  yield (x._2) :: decode(xs)
7                   }
8 }

抱歉,我开始使用 Scala。有人可以解释为什么会发生这种情况以及如何解决它吗?

4

5 回答 5

4

主要问题是您用于连接列表的运算符 -::仅用于将单个元素添加到列表中,因此在您的代码中,您试图将 yield 的结果(本身就是一个序列)添加到 aList[A]并获取类型结果不兼容。这是一个可以工作的修改版本 - 它使用++:可用于将两个序列连接在一起的运算符。我还将 theyield移到了单独的语句中,否则您需要在 yield 周围加上括号,以便++:对 the 的完整结果起作用,yield而不是对每个元素起作用(由于类型不匹配,这将再次无法编译)。

def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
  case Nil => Nil
  case x :: xs => {
    val repeatedElems = for {
      i <- 1 to x._1
    }  yield (x._2)
    repeatedElems ++: decode(xs)
  }
}
于 2013-10-28T22:29:38.280 回答
4

你很接近 - 只有几个问题。这是我想出的固定版本:

def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
   case Nil => Nil
   case x :: xs => (for {
                       i <- 1 to x._1
                    } yield (x._2)).toList ::: decode(xs)
}

第一个 - 可能也是最重要的 - 是在 for-yield 周围的额外括号。没有这个,您将尝试 yield (x._2) :: decode(xs),而不仅仅是(x._2)(为了弥补这一点,{}可以省略整个 case 的周围)。

接下来,for-yield 生成 IndexedSeq 而不是 List,所以我强制转换为 List(您可以通过各种方式处理这个问题,这只是最权宜之计)。

最后,连接到 List fromdecode(xs)需要:::操作符(您也可以使用++)而不是::(预先添加单个条目,而不是子列表)。

于 2013-10-28T22:23:36.010 回答
2

其他答案非常好,但我认为生成解码列表需要更少的语法,并且与表达式List.fill 相比更容易理解。for-yield

def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
   case Nil => Nil
   case x :: xs => List.fill(x._1)(x._2) ::: decode(xs)
}

输出:

scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)))
res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
于 2013-10-28T23:43:31.910 回答
0

另一种方法是使用地图:

def decode[A](l: List[(Int, A)]): List[A] = {
  val l1: List[List[A]] = l map { e =>
    List.fill(e._1)(e._2)
  }
  l1.flatten
} 
于 2013-10-29T01:30:02.680 回答
0

这是布赖恩答案的略微修改版本。分解元组使代码更具可读性:

def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
   case Nil => Nil
   case (count, letter) :: xs => List.fill(count)(letter) ::: decode(xs)
}
于 2013-10-29T00:02:05.293 回答