scala - 使用scala计算字符串中相邻的重复字符

标签 scala

我需要使用 scala 打印字符串中相邻的重复字符及其计数。
例如: aaabbcda = 3a2b1c1d1a
我试过的是

object StringTransformation extends App {
  
   val str = "aaabbcda"
   strTransform(str)
  
   def strTransform(str:String) {
     var count = 1
     for (i <- 1 until str.length) {
        if(str.charAt(i-1) == str.charAt(i)){
            count += 1
        }else{
            print(count+String.valueOf(str.charAt(i-1)))      
            count=1
        }
     }
     print(count+str.takeRight(1))
   }
}
尽管这是有效的,但这是程序化的,牢记命令式方法。
有人可以建议使用 map() 或其他一些方法的功能方法。

最佳答案

函数式编程非常重视分解问题。在您的情况下,您的问题包括三个主要步骤

  • 查找和计算相邻字符
  • 使用字符前的计数格式化字符串
  • 将结果打印到屏幕

  • (1) 可以是它自己的函数,(2) 用 map 很容易做到,而 (3) 是一个简单的 println在这一切的最后。
    (1) 将是最复杂的。我假设我们有一个 List (在不同的 Scala 集合类型之间转换相对简单,列表非常适合练习递归)。
    // group() takes a list and a grouping function and returns the
    // collection of adjacent elements, grouped by the function. In our
    // case, the function will simply be the identity function, but we
    // could also use it to define an equivalence class. For instance, if
    // the function was toUpper or toLower, then our grouping would be
    // case-insensitive.
    def group[A, B](lst: List[A])(f: A => B): List[(B, Int)] = {
      // This is our recursive helper function. It's defined in here
      // because it's only useful in here. We keep track of the current
      // element we're looking at and how many times we've seen it.
      def go(curr: B, count: Int, xs: List[A]): List[(B, Int)] = {
        // This is roughly your imperative solution, but written
        // recursively and in more generality. We check if the next
        // element is equal to our "current" element and branch
        // accordingly.
        xs match {
          case Nil => List((curr, count))
          case x :: xs =>
            if (f(x) == curr) {
              go(curr, count + 1, xs)
            } else {
              (curr, count) :: go(f(x), 1, xs)
            }
        }
      }
      // If the list starts out empty, there's no need to recurse. If the
      // list is non-empty, then start at the beginning.
      lst match {
        case Nil => Nil
        case x :: xs => go(f(x), 1, xs)
      }
    }
    
    现在,要调用它,
    val str = "aaabbcda"
    println(group(str.toList) { x => x }.map { case (b, n) => s"$n$b" }.mkString)
    
    首先,我们使用 toList 将字符串转换为字符列表。 .一旦我们有了一个列表,我们就调用我们的 group()具有用于比较键的标识函数的函数(因此一个字符只与自身比较)。后 group()打电话,我们有List((Char, Int)) .
    然后我们打电话map在该列表中以您想要的方式将其格式化为字符串。这给了我们一个 List(String) , 和 mkString将这些字符串连接在一起。最后,我们println字符串。
    此函数目前不是尾递归的。稍加努力,我们可能会使其成为尾递归,或者,如评论所示,尝试将我定义的递归函数转换为使用 foldLeft 的递归函数是一个很好的练习。 .但这是一个开始;我刚刚编写的所有代码都不依赖于可变性或传统的命令式循环结构。这是您在 Haskell 之类的语言中会看到的那种代码。

    关于scala - 使用scala计算字符串中相邻的重复字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68084819/

    相关文章:

    javascript - 如何通过scala-js创建JS库

    java - 创建一个 backtype.storm.tuple.Tuple 用于测试目的?

    scala - SBT:启动非默认项目主类的命令行 'run'

    scala - 如何在scala中声明空列表然后添加字符串?

    scala - Spark如何避免for循环?

    scala - 从 Scala 解析器组合器中过滤标记

    scala - Scala 是否足以用于 native 、系统和内核编程?

    scala - 用Filter代替过滤器

    scala - Specs2:如何测试具有多个注入(inject)依赖项的类?

    scala - 磁铁图案和重载方法