Counting occurences of characters in a String using tail recursion

孤街浪徒 提交于 2020-01-07 09:42:56

问题


I have no clue how to count the occurrences of characters in a string using tail recursion in scala.

I need to run a program with input

times(explanation)

and the output is:

List((e,1), (x,1), (p,1), (l,1), (a,2), (n,2), (t,1), (i,1), (o,1))

I tried running RLE so far but the topic of tail recursion is new to me, so some steps/algorithm for doing so would be perfect


回答1:


Possible Solutions:

A String is a list of characters. Group them by identity which is (x => x), then count them. Normally groupBy returns a Map which can by transformed to a list of tuples by toList.

Code/ not reinventing the wheel

def times(s: String) = s.groupBy(identity).mapValues(_.size).toList 
times: (s: String)List[(Char, Int)]

Example

times("explanation")
res1: List[(Char, Int)] = List((e,1), (x,1), (n,2), (t,1), (a,2), (i,1), (l,1), (p,1), (o,1))

Code with tail recursion / reinvents the wheel/ please use not to cheat in the Coursera Scala Course

import scala.annotation.tailrec

def myTimes(s: String) : List[(Char,Int)] = {

  @tailrec // comiler cheks if really tailrecursive
  def timesTail(chars: List[Char], res: List[(Char,Int)])  : List[(Char,Int)] = 
    chars match {
      case Nil => res      // we are done when there are no characters left
      case char :: rest => {
          // otherwise 
          val newCharCount = 
            res.
              find (_._1 == char). //check if we already have seen the character
              map{ case (c,count) => (c,count + 1)  }. // if yes, we raise take the old count and raise it by one
              getOrElse( (char,1) ) // otherwise we count one occurrence
          // here it gets recursive 
          timesTail(
                rest, // remaining Characters
                newCharCount :: res.filterNot(_._1 == char) // add the new count to list, remove old if present
          )
      }
    }
  // initial call with empty lsit to start the helper function  
  timesTail(s.toList,List())

}



回答2:


Efficient, this is not. But it is tail-recursive, and the output is in the same order as in the question, in case that matters. If this isn't an assignment then Andreas's groupBy solution is the better solution.

  def times(s: String) = {
    def timesRecurse(s: String, result: List[(Char, Int)]): List[(Char, Int)] = {
      if (s.isEmpty)
        result
      else {
        val c = s.head
        val i = result.indexWhere(_._1 == c)
        timesRecurse(s.tail,
           if (i == -1) 
              (c, 1) :: result
           else
             result updated (i, (c, result(i)._2 + 1)))
      }

    }
    timesRecurse(s, List[(Char, Int)]()).reverse
  }

  times("explanation")
  //> res0: List[(Char, Int)] = 
  // List((e,1), (x,1), (p,1), (l,1), (a,2), (n,2), (t, 1), (i,1), (o,1))


来源:https://stackoverflow.com/questions/26502978/counting-occurences-of-characters-in-a-string-using-tail-recursion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!