Scala 函数式编程实例-文本文件中单词视频统计(WordCount)
Scala 是一门现代多范式编程语言,以一种简洁,优雅,类型安全的方式表达通用编程模式。它将面向对象和函数式语言十分自然地结合到了一起。
下面结合一个综合应用的例子,对某个目录下所有文件中的单词进行词频统计,以Scala 语言实现。
完整代码如下:
// 导入需要的类
import java.io.File
import collection.mutable.Map // 需要使用可变映射,因此明确调入mutable Map
import scala.io.Source
// 创建单例对象Singleton Object
object WordCount1 {
// main方法是程序执行入口
def main(args: Array[String]): Unit = {
// 读取当前文件下testfiles 目录中的文本文件
val dirfile = new File("testfiles")
// 获取所有文件对象构成的数组
val files = dirfile.listFiles
// 建立可变的空的Map对象results,用来保存统计结果
val results = Map.empty[String, Int]
// 对文件对象进行循环
for(file <- files) {
// 从File 对象建立Source对象,方便文件的读取
val data = Source.fromFile(file)
// getLines方法返回文件各行构成的迭代器对象,类型为 Iterator[String]
// flatMap 进一步将每一行字符串拆分成单词,再返回所有这些单词构成的新字符串迭代器
val strs = data.getLines().flatMap(s=>s.split(" "))
// 进行遍历,在匿名函数中,对应当前遍历的某个单词,如果之前统计过,就+1,;如果没有统计过,则创建一个新的Map条目,并赋值为1。
strs foreach {
word => if(results.contains(word)) {
results(word) += 1
} else {
results(word) = 1
}
}
}
// 输出统计结果
results foreach{case (k, v)=>println(s"$k:$v")}
}
}
在IDEA中运行,输出结果:
发现结果中:(1)没有处理大小写;(2)标点符号没有处理;(3)空白字符串也没有处理。
针对上述问题,可以进行优化一下代码。
在单例对象中,添加如下函数的定义。
// 移除标点符号,转换为小写字符
val removePunctuation: String => String = (text: String) => {
val punctPattern = "[^a-zA-Z0-9\s]".r
punctPattern.replaceAllIn(text, "").toLowerCase
}
同时,还需要调整如下代码行。
val strs = data.getLines().flatMap(s=>s.split(" ")).map(removePunctuation).filter(_!="")
从输出结果中发现,上述三个问题已经结果。
如果想进一步对输出结果,按照词频数据从大到小排序呢?可以进一步改进代码。
// 输出统计结果
results foreach{case (k, v)=>println(s"$k:$v")}
针对输出统计结果代码,进行改进,增加排序功能:
// 输出统计结果,按照词频倒序输出
results.toList.sortBy(_._2).reverse foreach{case (k, v)=>println(s"$k:$v")}
再次运行改进后的代码,验证输出结果:
现在输出结果达到了预期。