Scala 相当于 Haskell 的 insertWith for Maps

Scala equivalent of Haskell's insertWith for Maps

我想做一个简单的任务,计算字符串中的单词数。我发现的最简单的方法是使用地图来跟踪词频。之前使用 Haskell,我使用它的 Map 的函数 insertWith,它采用解决键冲突的函数,以及键和值对。不过,我在 Scala 的库中找不到类似的东西;只有一个添加函数(+),它可能会在重新插入密钥时覆盖以前的值。不过,出于我的目的,我不想覆盖以前的值,而是想给它加 1 以增加它的计数。

显然我可以编写一个函数来检查一个键是否已经存在,获取它的值,向它加 1,然后重新插入它,但奇怪的是没有包括这样的函数。我错过了什么吗? Scala 的做法是什么?

使用具有默认值的地图,然后使用 +=

进行更新
import scala.collection.mutable

val count = mutable.Map[String, Int]().withDefaultValue(0)
count("abc") += 1
println(count("abc"))

如果是字符串那么为什么不使用拆分模块

import Data.List.Split

let mywords = "he is a good good boy"
length $ nub $ splitOn " " mywords
5

如果您想坚持 Scala 的不可变风格,您可以创建自己的具有不可变语义的 class:

class CountMap protected(val counts: Map[String, Int]){
    def +(str: String) = new CountMap(counts + (str -> (counts(str) + 1)))
    def apply(str: String) = counts(str)
}

object CountMap {
    def apply(counts: Map[String, Int] = Map[String, Int]()) = new CountMap(counts.withDefaultValue(0))
}

然后就可以使用了:

val added = CountMap() + "hello" + "hello" + "world" + "foo" + "bar"
added("hello")
>>2
added("qux")
>>0

您还可以在伴生对象上添加 apply 重载,这样您就可以直接输入一个单词序列,甚至一个句子:

object CountMap {
    def apply(counts: Map[String, Int] = Map[String, Int]()): CountMap = new CountMap(counts.withDefaultValue(0))
    def apply(words: Seq[String]): CountMap = CountMap(words.groupBy(w => w).map { case(word, group) => word -> group.length })
    def apply(sentence: String): CountMap = CountMap(sentence.split(" "))
}

然后您可以更轻松地:

CountMap(Seq("hello", "hello", "world", "world", "foo", "bar"))

或:

CountMap("hello hello world world foo bar")