【问题标题】:count char frequency in string with scala用scala计算字符串中的字符频率
【发布时间】:2016-05-08 23:40:13
【问题描述】:

我寻找一种方法来计算字符串中的不同字符。 问题是 不允许使用 scala-api 中的任何函数或使用 vars(仅限 val)。

我想要同样的结果

val fruit: String = "dasisteintest"
println(fruit.groupBy(identity).mapValues(_.size))
Map(e -> 2, s -> 3, n -> 1, t -> 3, a -> 1, i -> 2, d -> 1)

在我所做的每一次尝试中,我最后都有一个list[(Char,Int)],我必须在其中更改 Int.但是因为它是一个不可变的列表,所以我无法更改它。 如何实现该计数字符算法?

【问题讨论】:

  • 不清楚您的实际问题是什么。假设你不只是在有人为你回答你的任务之后,你在哪里卡住了?输出应该是什么样子? Map(和 groupBy)是 scala-api 的一部分,所以不清楚你想要什么。你能用什么?
  • 正如我在上面所写的,我需要 相同的结果,例如 fruit.groupBy(identity).mapValues(_.size),但 没有来自 scala-api 的函数。我所有的尝试都失败了,因为每次我需要更改列表的一个元素。我知道我“只”必须使用已更改的元素创建新列表。但我不知道如何实现它以使用更改的元素创建一个新列表。所以我希望有人可以帮助我更改列表的元素(没有来自 api 的函数),或者有人有其他方法来计算字符串中的不同字符......希望现在一切都清楚了吗?

标签: scala


【解决方案1】:

你可以使用下面的sn-p:

val fruit: String = "dasisteintest"
val map = scala.collection.mutable.HashMap.empty[Char, Int]
for (symbol <- fruit) {
  if (map.contains(symbol))
    map(symbol) = map(symbol) + 1
  else
    map.+=((symbol, 1))
}
println(map)

【讨论】:

  • 嗯,很酷,谢谢!我认为自己编写 contains 方法并不难。我马上试试。
  • 我的猜测是答案不应该使用可变集合,但只有 OP 肯定知道。
  • @The-archetypal-paul 从问题的倒数第二句话中可以推断出该集合应该被更改。
  • @theoretisch 您可以使用 Java 的 HashMap(绝对不是 scala api)来不实现 contains+= 方法。
  • @Aliaxander,可以。不过,我会推断 OP 尚未了解如何使用不可变集合执行此操作,只是不知道如何在不修改列表的情况下执行此操作。我猜这就是任务的重点。由于不允许使用 vars,我的猜测是可变集合也不是。
【解决方案2】:
def countChars(str: String) = {
  def loop(chars: List[Char], acc: Map[Char, Int]): Map[Char, Int] = {
    chars match {
      case Nil => acc
      case char :: rest =>
        loop(rest, acc + (char -> (acc(char) + 1)))
    }
  }

  loop(str.toList, Map.empty[Char, Int] withDefaultValue 0)
}

测试:

@ val fruit: String = "dasisteintest" 
fruit: String = "dasisteintest"
@ countChars(fruit) 
res4: Map[Char, Int] = Map('e' -> 2, 's' -> 3, 'n' -> 1, 't' -> 3, 'a' -> 1, 'i' -> 2, 'd' -> 1)

您在此处使用的任何内容都来自 scala api、Map.applyMap.emptyList.::。很难不使用 scala api 中的 any 函数。我的猜测是你不应该使用像groupBy 这样的东西,你应该做一些更底层的事情。折叠是这里的自然解决方案,例如 foldLeft,但如果这被认为是“使用 scala api 中的函数”,您可以自己实现 foldLeft,就像我在解决方案中所做的那样。

至于withDefaultValue,你可以用显式检查值是否存在来替换它,并在这种情况下放一个1。

您不知道如何更改不可变的列表或映射中的元素?您只需创建一个更改该值的新列表。

对于地图,给定

val map = Map('a' -> 3)

你可以更新它

@ map.updated('a', 4) 
res6: Map[Char, Int] = Map('a' -> 4)

@ map + ('a' -> 4) 
res7: Map[Char, Int] = Map('a' -> 4)

两者都做完全相同的事情 - 插入或更新 - 并返回新地图。

在这里您可以找到如何更新列表中的元素

Replace element in List with scala

虽然您很少希望按索引访问列表,但您宁愿只是从旧列表构建一个新列表,同时以某种方式对其进行迭代,例如折叠。

【讨论】:

  • 谢谢,匹配的解决方案很酷。这解决了我的 List 完美的问题。
【解决方案3】:

“没有来自 Scala API 的函数”是什么意思?这不包括 collections api 中的任何功能吗?如果是这样,请忽略我的回答。但是,如果我们甚至不能使用 reduce 方法,我看不出这个练习的意义。

这是我想出的:

val fruit: String = "dasisteintest"
fruit.foldLeft[Map[Char,Int]](Map.empty)((map, c) => map + (c -> (map.getOrElse(c, 0) + 1)))

虽然你可以扩展“你必须改变 Int”的意思吗?

【讨论】:

  • 谢谢,但是 .foldLeft 和 .getOrElse 是来自 scala api 的函数,不是吗?如果我想像你一样实现它,我必须自己编写这些函数......
  • 你对 Scala API 的分配定义是什么
  • 定义只是“不要使用scala-api中的函数”..你认为函数之间有什么区别吗?
【解决方案4】:

这是预期的代码。 首先是从列表中返回字符的函数

    def removeFromList(l: List[Char], l2: List[Char], toDelete: Char): List[Char] = {
       if (l.isEmpty) l2
       else {
           if (l.head == toDelete)
              removeFromList(l.tail, l2, toDelete)
           else 
              removeFromList(l.tail, l2 :+ l.head, toDelete)
       }
    }

然后是计算字符并调用removeFromList()的函数

def zaehlZeichen(s: String): List[(Char, Int)] = {
    val sl: List[Char] = s.toUpperCase().toList
    if (sl.isEmpty) Nil
    else {
      val l: List[Char] = List()
      val tupleList: List[(Char, Int)] = List();
      val in: Int = countChar(sl, 0, sl.head)
      val t: List[(Char, Int)] = tupleList :+ (sl.head, in)
      val cutL: List[Char] = removeFromList(sl, l, sl.head)
      t ::: zaehlZeichen(cutL.mkString);
    }
  }

【讨论】:

    【解决方案5】:
    object CountEachCharInString 
    {
      //Counts the number of a specific character in the Input String
      def characterCount(inputChar: Char, str: String): Unit = 
      {
        var num: Int = 0
        num = str.count(_ == inputChar);
        
    /*
        //Implementation of count method
        for(i <- 0 to str.length - 1)
        {
          if(str(i) == inputChar) 
          {
            num += 1
          }
        }
    */
        println(s"$inputChar appears $num times")
      }
      
      
      def countAllChars(inputStr: String): Unit = 
      {
        
        //To eliminate duplicates, need one loop inside the other. str(i) == str(j)
        for(i <- 0 to inputStr.length - 1)
        {
          var occurence: Int = 0
          
          for(j <- 0 to i-1)
          {
            if(inputStr(j) == inputStr(i))
                occurence = occurence + 1
          }
          
          if(occurence == 0)
          {
            characterCount(inputStr(i), inputStr)
            //var num = inputStr.count(_ == inputStr(i))
            //println( inputStr(i) + s" appears $num times")
          }        
        }
      }
      
      
      def main(args: Array[String]): Unit =
      {
        countAllChars("HelloforHello...^^&&&&")
      }
    }
    

    【讨论】:

    • 问题明确指出,"不允许...使用 vars (only val)".
    • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-18
    • 2017-04-19
    • 1970-01-01
    • 2011-10-06
    • 2019-08-07
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多