转换列表计数重复元素

时间:2016-04-14 00:48:49

标签: scala

我尝试使用递归从here解决问题13,但是我收到了错误(我不明白)。

问题是:

给出以下列表List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)

我需要返回重复的元素并计算:

List((4,'a), (1,'b), (2,'c), (2,'a), (1,'d), (4,'e))

这是我的代码:

object P13 extends App  {

    val ls2 = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)

    println(ls2)
    println(encodeDirect(ls2))

    def encodeDirect[A](ls: List[A]): List[(Int,A)] = ls match {
        case h :: tail => (ls.takeWhile( _ == h ).count(_), h)  +: encodeDirect (ls.dropWhile ( _ == h ) ) 
        case Nil => Nil
    }

}

这是错误:

P13.scala:18: error: type mismatch;
 found   : List[(Any, A)]
 required: List[(Int, A)]
        case h :: tail => (ls.takeWhile( _ == h ).count(_), h)  +: encodeDirect
(ls.dropWhile ( _ == h ) )
                                                                ^
one error found

为什么会发生这种情况以及如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

您的错误非常简单,您使用count代替size / length

  def encodeDirect[A](ls: List[A]): List[(Int,A)] = ls match {
    case h :: tail => (ls.takeWhile( _ == h ).size, h)  +: encodeDirect (ls.dropWhile ( _ == h ) )
    case Nil => Nil
  }

count获取谓词并计算与该谓词匹配的元素数,而size只返回集合的长度。

只是为了好玩,这里有一个替代方案,利用span将集合分解为前缀/后缀:

def encodeDirect[A](ls: List[A]): List[(Int,A)] =
   ls.headOption.map(h => ls.span(h == _)).toList
     .flatMap { case (pref, t) => (pref.size, pref.head) :: encodeDirect(t) }

使用结果累加器作为参数,以尾递归方式重写此函数也是一个好主意,因为尾递归在scala中更有效。

答案 1 :(得分:0)

另一种方法,使用span

def encode(xs: List[Symbol]): List[(Int,Symbol)] = xs match {
  case Nil => Nil
  case x :: xss => val (g,rest) = xs.span(_ == x)
                   (g.size,g.head) +: encode(rest) 
}

我们首先将列表分成与头部相同的项目,然后是其余部分。

相关问题