Scala 字符串中唯一字符的计数

Scala 字符串中唯一字符的计数,scala,Scala,我需要编写一个函数,在给定一个输入字符串的情况下,返回(Char,Int)对的列表 我的解决方案产生了正确的结果,但我想知道是否有更好的方法: def countChars(s: String): List[(Char, Int)] = { s.groupBy(c => c.toLower).flatMap(e => List((e._1, e._2.length))).toList }

我需要编写一个函数,在给定一个输入
字符串的情况下,返回
(Char,Int)
对的
列表

我的解决方案产生了正确的结果,但我想知道是否有更好的方法:

def countChars(s: String): List[(Char, Int)] = {
    s.groupBy(c => c.toLower).flatMap(e => List((e._1, e._2.length))).toList
  }                                              
这会在工作表中产生如下结果:

countChars("Green Grass")
// res0: List[(Char, Int)] = List(('e', 2), ('s', 2), ('n', 1), ('a', 1), (' ', 1), ('g', 2), ('r', 2))

制作一个单例列表只是为了将其展平是多余的

"Green Grass".groupBy(c => c.toLower).map(e => (e._1, e._2.length)).toList

如果您正在处理长字符串或字符流,那么您的方法将不必要地使用太多内存-在调用
flatMap
之前,您基本上是在存储输入字符串中的所有字母。相反,您可以只存储每个字母的出现次数:

import scala.collection.immutable.Map
"Green Grass".map(_.toLower).foldLeft(Map.empty[Char, Int]) { (m, char) =>
  val count = m.getOrElse(char, 0)
  m.updated(char, count+1)
}.toList

这将返回与您的解决方案相同的结果。

稍微美化一下的@dhg asnwer版本:

"Green Grass".groupBy(c => c.toLower).mapValues(group => group.length).toList

你也可以试试这个

def countChars(s: String) =
  s.distinct.map(c => c -> s.count(_ == c))

Scala 2.13
开始,我们可以使用该方法,它是
groupBy
/
mapValues
的一种一次性替代方法:

"Green Grass".groupMapReduce(_.toLower)(_ => 1)(_ + _).toList
// List[(Char, Int)](('e', 2), ('s', 2), ('n', 1), ('a', 1), (' ', 1), ('g', 2), ('r', 2))
这:

  • 按小写版本对字符进行分组(
    .toLower
    )(分组部分为MapReduce)

  • 映射
    s每个分组值出现1(
    \u=>1
    )(映射组的一部分映射减少)

  • reduce
    s一组值(
    \uu+\uu
    )中的值,方法是将它们相加(reduce-part-of-groupMapreduce

  • 使用
    .toList
    将生成的
    映射[Char,Int]
    转换为
    列表[(Char,Int)]

groupMapeduce
阶段是一个可以通过以下方式进行翻译的阶段:

"Green Grass".groupBy(_.toLower).mapValues(_.map(_ => 1).reduce(_+_))

说得好。出于某种原因,我认为我必须使用平面图,所以为了使它能够正常工作,我必须为每个结果列出清单。@nietaki的答案看起来也很有趣。这将线性运算转化为二次运算,对每个
c
遍历
s
。仅供参考:您不需要导入
不可变。Map
。它总是由
Predef
自动加载,我知道,我只是想指出我使用的
映射:)