【问题标题】:Do word count by taking input from file line by line in Scala?通过在 Scala 中逐行从文件中获取输入来计算字数?
【发布时间】:2017-11-16 22:53:35
【问题描述】:

我有一个包含单词的源文件并想要进行典型的字数统计,我正在使用转换为数组并进入内存的东西

def freqMap(lines: Iterator[String]): Map[String, Int] = {

   val mappedWords: Array[(String, Int)] = lines.toArray.flatMap((l: String) => l.split(delimiter).map((word: String) => (word, 1)))

   val frequencies = mappedWords.groupBy((e) => e._1).map { case (key, elements) => elements.reduce((x, y) => (y._1, x._2 + y._2)) }

   frequencies
}

但我想逐行评估并在处理每一行时显示输出。这怎么能懒惰地完成,而不把所有的东西都放在内存中

【问题讨论】:

    标签: scala functional-programming immutability


    【解决方案1】:

    您说您不想将所有内容都放在内存中,但您想“在处理每一行时显示输出”。听起来您只想println 中间结果。

    lines.foldLeft(Map[String,Int]()){ case (mp,line) =>
      println(mp)  // output intermediate results
      line.split(" ").foldLeft(mp){ case (m,word) =>
          m.lift(word).fold(m + (word -> 1))(c => m + (word -> (c+1)))
      }
    }
    

    迭代器 (lines) 一次被消耗一个。 Map 结果是逐字构建的,并作为foldLeft 累加器逐行结转。

    【讨论】:

    • 对于大文件,我理解地图结果是逐字构建的,效率会受到影响吗?
    • 不确定我是否理解您的问题。结果Map 是逐字构建的,但还能怎么做呢?即使您要将整个文件加载到内存中(不推荐用于非常大的文件),在空白处拆分,然后 groupBy(identity),仍然一次生成一个单词的结果。它只是隐藏了一些细节。我提到逐字程序只是为了标记与报告中间结果的逐行处理的区别。如果您没有将所有内容都加载到内存中,是否可以提高效率。
    【解决方案2】:

    我认为您正在寻找的是 scanLeft 方法。所以示例解决方案可能如下所示:

    val iter = List("this is line number one", "this is line number two", "this this this").toIterator
    
      val solution = iter.flatMap(_.split(" ")).scanLeft[Map[String, Int]](Map.empty){
        case (acc, word) =>
          println(word)
          acc.updated(word, acc.getOrElse(word, 0) + 1)
      }
    

    如果你执行 val solution = iter.flatMap(_.split(" ")).scanLeftMap[String, Int]{ 大小写(acc,单词)=> 打印(字) acc.updated(word, acc.getOrElse(word, 0) + 1) }

    println(solution.take(3).toList) 这将被打印到控制台:

      val solution = iter.flatMap(_.split(" ")).scanLeft[Map[String, Int]](Map.empty){
    case (acc, word) =>
      println(word)
      acc.updated(word, acc.getOrElse(word, 0) + 1)
    

    }

    this
    is
    line
    number
    one
    List(Map(), Map(this -> 1), Map(this -> 1, is -> 1), Map(this -> 1, is -> 1, line -> 1), Map(this -> 1, is -> 1, line -> 1, number -> 1))
    

    【讨论】:

    • 在scanLeft地图每次都返回一张新地图?
    • 你得到的是 Map[String, Int] 的惰性迭代器。它以零元素、空映射开始,然后具有后续状态。所以它就像一个 foldLeft,存储所有中间状态。
    猜你喜欢
    • 1970-01-01
    • 2021-12-04
    • 2014-01-22
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多