为加强对函数式编程的理解,同时巩固Scala语法,这里分析一个实例:对某个目录下所有文件中的单词进行词频统计。
【源码】
import java.io.File
import scala.io.Source
import collection.mutable.Map
object WordCount{
def main(args: Array[String]){
val dirfile = new File("testfiles")
val files = dirfile.listFiles
val results = Map.empty[String,Int]
for(file <- files){
val data = Source.fromFile(file)
val strs = data.getLines.flatMap{s => s.split(" ")}
strs foreach{
word =>
if(results.contains(word)) results(word)+=1 else results(word)=1
}
}
results foreach{case (k,v) => println(s"$k:$v")}
}
}
【分析】
- 行1~3:导入需要的类。
- 行6:
val dirfile = new File("testfiles")
建立一个File对象,这里假设当前文件夹下有个testfiles文件夹,且里面包含若干文本文件。
-
行7:
val files = dirfile.listFiles
调用File对象的listFiles方法,得到其下所有文件对象构成的数组,file的类型为Array[java.io.File]。
-
行8:
val results = Map.empty[String,Int]
建立一个可变的空的映射(Map)对象results,保存统计结果。映射中的条目都是一个(key,value)键值对,其中,key是单词,value是单词出现的次数。(映射是指通过对容器中的元素进行某些运算来生成一个新的容器。两个典型的映射操作是map方法和flatMap方法。)
-
行9:
for(file <- files){
通过for循环对文件对象进行循环,分别处理各个文件。
-
行10:
val data = Source.fromFile(file)
从File对象建立Source对象,方便文件的读取。
-
行11:
val strs = data.getLines.flatMap{s => s.split(" ")}
getLines方法返回文件各行构成的迭代器对象,类型为Iterator[String],flatMap进一步将每行字符串拆分成单词,再返回所有这些单词构成的新字符串迭代器。
-
行12~15:
strs foreach{ word => if(results.contains(word)) results(word)+=1 else results(word)=1 }
对上述的字符串迭代器进行遍历,在匿名函数中,对于当前遍历到的某个单词,如果这个单词以前已经统计过,就把映射results中以该单词为key的映射条目的value增加1。如果以前没有被统计过,则为这个单词创建一个映射条目,只需要直接对应的key进行赋值,就实现了添加新的条目。
-
行17:
results foreach{case (k,v) => println(s"$k:$v")}
对Map对象results进行遍历,输出统计结果。