使用折叠计算字数

时间:2016-07-12 21:11:02

标签: scala

如何将单词列表计入Map结构中,其中Int是count,String是当前单词。

我正在尝试使用折叠,但这是我最接近的:

val links = List("word1" , "word2" , "word3")
links.fold(Map.empty[String, Int]) ((count : Int, word : String) => count + (word -> (count.getOrElse(word, 0) + 1)))

导致错误:

value getOrElse is not a member of Int

4 个答案:

答案 0 :(得分:2)

也许不是最有效的,但对我来说最明智的方式是:

val grouped = links groupBy { identity } // Map[String, List[String]]
val summed = grouped mapValues { _.length } // Map[String, Int]

println(grouped) // Map(word2 -> List(word2, word2), word1 -> List(word1))
println(summed) // Map(word2 -> 2, word1 -> 1)

答案 1 :(得分:2)

如果你看看折叠的签名,你可以看到

links.fold(Map.empty[String, Int]) ((count : Int, word : String) => ???)

不会编译

<{1}}上的

折叠类型为List[A]

这不是你可以使用的东西; fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1不是Map.empty[String, Int]

的子类型

您需要的是StringfoldLeft

您的foldLeft[B](z: B)(op: (B, A) ⇒ B): BA。您的StringB,但是在您的第二个参数列表中,您Map[String, Int]并不符合签名。它应该是(Int, String) => ???

立即出现解决方案:

(Map[String, Int], String) => Map[String, Int]

总而言之,你有

(map: Map[String, Int], next : String) => map + (next, map.get(next).getOrElse(0) + 1)

答案 2 :(得分:1)

您需要使用foldLeft:

val links = List("word1" , "word2" , "word3", "word3")
val wordCount = links.foldLeft(Map.empty[String, Int])((map, word) => map + (word -> (map.getOrElse(word,0) + 1)))

答案 3 :(得分:1)

这是一个例子,其中catsscalaz这样的库的一些抽象是有用的,并提供了一个很好的解决方案。

我们可以将"foo"代表Map("foo" -> 1)。如果我们可以将这些地图组合成所有单词,那么我们最终会得到单词count。这里的关键字是 combine ,它是Semigroup中定义的函数。我们可以使用此函数将我们单词列表的所有地图组合在一起使用combineAll(在Foldable中定义并为您进行折叠)。

import cats.implicits._

val words = List("a", "a", "b", "c", "c", "c")

words.map(i => Map(i -> 1)).combineAll
// Map[String,Int] = Map(b -> 1, a -> 2, c -> 3)

或使用foldMap一步完成:

words.foldMap(i => Map(i -> 1))
// Map[String,Int] = Map(b -> 1, a -> 2, c -> 3)