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")
我想做一个简单的任务,计算字符串中的单词数。我发现的最简单的方法是使用地图来跟踪词频。之前使用 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")