Scala如何按元素出现次数分组?是否有对应内置函数?
在Scala中按元素出现次数分组的实现方法
当然有办法实现!Scala的标准集合库虽然没有直接提供一个一步到位的函数,但通过几个常用方法的组合,就能轻松得到你想要的结果。咱们结合你的例子一步步来:
首先,先看你的输入列表:
val x = List("c", "b", "b", "c", "a", "d", "c")
步骤1:分组相同元素
用groupBy(identity)可以把列表中相同的元素归为一组,返回一个Map,键是元素本身,值是该元素组成的子列表:
x.groupBy(identity) // 结果:Map(c -> List(c, c, c), b -> List(b, b), a -> List(a), d -> List(d))
步骤2:统计每组元素的数量
接着用mapValues(_.size)把每个子列表转换成它的长度(也就是元素的出现次数),这样就得到了元素和对应次数的映射:
x.groupBy(identity).mapValues(_.size) // 结果:Map(c -> 3, b -> 2, a -> 1, d -> 1)
步骤3:转换成列表并排序
把上面的Map转换成列表,再按次数降序排序(这样次数多的元素排在前面),最后调换元组的顺序让次数在前:
val result = x.groupBy(identity) .mapValues(_.size) .toList .sortBy(-_._2) // 用负号实现降序 .map { case (elem, count) => (count, elem) } // 最终结果:List((3, "c"), (2, "b"), (1, "a"), (1, "d"))
额外优化:保持元素首次出现的顺序
如果你的需求里,次数相同的元素需要按照它们在原列表中首次出现的顺序排列(就像你的示例里a在d前面),可以先记录每个元素第一次出现的索引,再结合排序:
// 先记录每个元素首次出现的位置 val firstOccurrence = x.zipWithIndex.foldLeft(Map[String, Int]()) { case (acc, (elem, idx)) => acc.getOrElseUpdate(elem, idx) } val orderedResult = x.groupBy(identity) .mapValues(_.size) .toList .sortBy { case (elem, count) => (-count, firstOccurrence(elem)) } .map { case (e, c) => (c, e) }
这样处理后,次数相同的元素就会严格按照它们第一次出现的顺序排列啦。
总的来说,Scala的集合操作非常灵活,通过groupBy、mapValues和排序方法的组合,完全能满足你的需求~
内容的提问来源于stack exchange,提问作者Dadou
相关产品推荐
相关产品推荐

