在循环中填充贴图[Scala]

在循环中填充贴图[Scala],scala,map,for-loop,Scala,Map,For Loop,恐怕这是另一个noob问题 我想做的是使用Map来计算单词在poe…m中出现的频率,然后将结果打印到控制台。 我使用了以下我认为有效的代码(虽然可能不太地道): val poe_m=“”有一次,在一个沉闷的午夜,当我思考着虚弱和疲惫时, |在许多稀奇古怪的被遗忘的传说中, |当我点点头,几乎要打盹的时候,突然传来了敲门声, |就像有人轻轻地敲打,敲打我的房门。 |`“有客人来了,”我咕哝着,“敲我的房门- |只有这个,没有别的 val分隔符=数组(“”、“”、“”、“-”、“\n”、“\“”、”

恐怕这是另一个noob问题

我想做的是使用
Map
来计算单词在poe…m中出现的频率,然后将结果打印到控制台。 我使用了以下我认为有效的代码(虽然可能不太地道):

val poe_m=“”有一次,在一个沉闷的午夜,当我思考着虚弱和疲惫时,
|在许多稀奇古怪的被遗忘的传说中,
|当我点点头,几乎要打盹的时候,突然传来了敲门声,
|就像有人轻轻地敲打,敲打我的房门。
|`“有客人来了,”我咕哝着,“敲我的房门-
|只有这个,没有别的
val分隔符=数组(“”、“”、“”、“-”、“\n”、“\“”、”)
var words=new collection.immutable.HashMap[String,Int]
for(word(words.getOrElse(word.toLowerCase,0)+1))
words.foreach(条目=>println(“单词:+entry.\u 1+”计数:+entry.\u 2))
据我所知,在Scala中,不可变的数据结构比可变的数据结构更受欢迎,
val
var
更受欢迎,因此我面临一个困境:
words
应该是
var
(允许在每次迭代中使用map的新实例)如果将结果存储在不可变的
Map
中,同时将
words
转换为
val
意味着使用可变的
Map


有人能告诉我如何正确处理这个存在的问题吗

在这种情况下,您可以使用
groupBy
mapValues

val tokens = poe_m.stripMargin.split(separators).filterNot(_.isEmpty)
val words = tokens.groupBy(w => w).mapValues(_.size)
更一般地说,这是一项工作:

 val words = tokens.foldLeft(Map.empty[String, Int]) {
   case (m, t) => m.updated(t, m.getOrElse(t, 0) + 1)
 }

给出了一些很好的示例。

在函数式编程中,最好使用一些不可变对象并使用函数来更新它们(例如返回更新映射的尾部递归函数)。但是,如果您不处理重载,那么您应该更喜欢可变映射而不是使用var,这不是因为它更强大(即使我认为应该是),而是因为它更易于使用


最后,特拉维斯·布朗的答案是解决你的具体问题,我的答案更像是个人哲学

我也是Scala的noob,所以可能有更好的方法。我提出了以下建议:

poe_m.stripMargin.split(separators)
     .filter(x => !x.isEmpty)
     .groupBy(x => x).foreach {
        case(w,ws) => println(w + " " + ws.size)
     }

通过应用连续函数,您可以避免对变量和可变项的需要,这是Martin Odersky在非常好的一本书《Scala编程:全面的分步指南,第二版》中所做的:

def countWords(text: String) = {
  val counts = mutable.Map.empty[String, Int]
  for (rawWord <- text.split("[ ,!.]+")) {
    val word = rawWord.toLowerCase
    val oldCount = 
      if (counts.contains(word)) counts(word)
      else 0
    counts += (word -> (oldCount + 1))
  }
  counts
}
def countWords(文本:字符串)={
val counts=mutable.Map.empty[String,Int]
用于(原始字(旧计数+1))
}
计数
}
然而,它也使用了一个可变的映射。

接下来的事情要归功于其他地方(特别是特拉维斯和丹尼尔),但有一个更简单的班轮需要离开

val words = poe_m split "\\W+" groupBy identity mapValues {_.size}
这里有一个简化,您不需要stripMargin,因为正如Daniel所建议的那样,正则表达式也处理了边距字符


您可以保留u.isEmpty筛选,以防止空字符串的边缘情况,如果需要,将产生(“->1”)

据我所知,编写
groupBy(identity)
比编写
groupBy(x=>x)
更好!正是我喜欢的答案:我的问题的具体解决方案和探索的新领域。不是
w=>w
可以使用
identity
对-我使用了显式identity函数以清晰明了,但值得注意的是
identity
是存在的。谢谢你的观点,因为我想找的是一个飞行员,而不是这个问题的解决方案。你应该使用
“\\W+”
来拆分。它包括所有不是字母或数字的东西。如果您还想丢弃数字,
“\\P{Alpha}+”
会这样做。
val words = poe_m split "\\W+" groupBy identity mapValues {_.size}