Scala入门系列之十三--针对容器的操作(遍历/映射/过滤/规约操作)

传送门
Scala入门系列之一--使用命令行往文件输入数据并读取数据
Scala入门系列之二--数组、元组、列表、集合数据类型简述
Scala入门系列之三--类和方法的创建以及命令行执行scala文件
Scala入门系列之四--类成员的可见性(private)以及用value和value_=进行读取和修改
Scala入门系列之五--主构造器和辅助构造器
Scala入门系列之六--伴生对象和伴生类
Scala入门系列之七--scala中的继承
Scala入门系列之八--scala中的特质(trait),也称接口
Scala入门系列之九--模式匹配两大法宝(match语句和case类)
Scala入门系列之十--包
Scala入门系列之十一--函数式编程基础
Scala入门系列之十二--高阶函数
Scala入门系列之十三--针对容器的操作(遍历/映射/过滤/规约操作)
Scala入门系列之十四--使用IDEA编写Scala代码并Maven打包提交集群运行
传送门

一、针对容器的操作

3.1)遍历操作:

Scala容器的标准遍历方法foreach

//def foreach[U](f:Elem => U):Unit

//方式一
val list = List(1,2,3)
val f=(i:Int) => println(i)
list.foreach(f)
//简化写法:“list foreach(i=>println(i))”或“list foreach println”

//方式二
val university = Map("XMU"->"Xiamen University","THU"->"Tsinghua University")
university foreach{kv => println(kv._1 + ":" + kv._2)}
//简化写法:university foreach{x=>x match{case (k,v) => println(k + ":" + v)}}
//简化写法:university foreach{case (k,v) => println(k + ":" + v)}  //使用foreach来实现对映射的遍历

3.2)映射操作:

概念简述:
映射是指通过容器中的元素进行某些运算来生成一个新的容器。两个典型的映射操作是map方法和flatMap方法。

map方法:将某个函数应用到集合中每个元素,映射得到一个新的元素,map方法会返回一个与原容器类型大小都相同的新容器,只不过元素的类型可能不同

val books = List("Hadoop","Hive","HDFS")
var a = books.map(s => s.toUpperCase)
//toUpperCase方法将一个字符串中的每个字母都变成大写字母
res56: List[String] = List(HADOOP, HIVE, HDFS)

var b = books.map(s => s.length) //将字符串映射到它的长度
res57: List[Int] = List(6, 4, 4) //新列表的元素类型为Int

flatMap方法(一对多映射):将某个函数应用到容器中的元素时,对每个元素都会返回一个容器(而不是一个元素),然后,flatMap把生成的多个容器“拍扁”成为一个容器并返回。返回的容器与原容器类型相同,但大小可能不同,其中元素的类型也可能不同

books flatMap(s => s.toList)
res58: List[Char] = List(H, a, d, o, o, p, H, i, v, e, H, D, F, S)

3.3)过滤操作:

概念简述
过滤:遍历一个容器,从中获取满足指定条件的元素,返回一个新的容器

filter方法:接受一个返回布尔值的函数f作为参数,并将f作用到每个元素上,将f返回真值的元素组成一个新容器返回

val l =  List(1,2,3,4,5,6) filter {_ % 2 = 0}
//使用了占位符语法,过滤能被2整除的元素
l: List[Int] = List(2, 4, 6)

3.4)规约操作:

概念简述
规约操作是对容器元素进行两两运算,将其“规约”为一个值

reduce方法:接受一个二元函数f作为参数,首先将f作用在某两个元素上并返回一个值,然后再将f作用在上一个返回值和容器的下一个元素上,再返回一个值,依此类推,最后容器中的所有值会被规约为一个值

val list  = List(1,2,3,4,5)
var a = list.reduce(_+_)//将列表元素累加,使用了占位符语法
//a: Int = 15

var b = list.reduce(_*_)//将列表元素连乘
//b: Int = 120

var c = list map (_.toString) reduce ((x,y)=>s"f($x,$y)")
//c: String = f(f(f(f(1,2),3),4),5) //f表示传入reduce的二元函数

3.4.1)补充

注意:规约操作中的reduceLeft和reduceRight方法是有区别的!
前者从左到右进行遍历,后者从右到左进行遍历(左是最左,右是最右。请注意看下图)

image.png

3.4.2)例子:

image.png

fold方法:一个双参数列表的函数,从提供的初始值开始规约。第一个参数列表接受一个规约的初始值,第二个参数列表接受与reduce中一样的二元函数参数(即头跟尾多了一个初始值

image.png
image.png

3.5)函数式编程实例WordCount

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 result = 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 result(word) += 1 result(word) = 1                
            }
        }
        results foreach{case(k,v) => println(s"$k:$v")}
    }
}


行1-3:导入需要的类;/行6:建立一个File对象,这里假设当前文件夹下有一个testfiles文件夹,且里面包含若干文本文件;
行7:调用File对象的listFiles方法,得到其下所有文件对象构成的数组,files的类型为Array[java.io.File];
行8:建立一个可变的空的映射(Map)对象results,保存统计结果。映射中的条目都是一个(key,value)键值对,其中,key是单词,value是单词出现的次数;
行9:通过for循环对文件对象进行循环,分别处理各个文件;
行10:从File对象建立Source对象(参见2.2.2节介绍),方便文件的读取;
行11:getLines方法返回文件各行构成的迭代器对象,类型为Iterator[String],flatMap进一步将每一行字符串拆分成单词,再返回所有这些单词构成的新字符串迭代器;
行12-15:对上述的字符串迭代器进行遍历,在匿名函数中,对于当前遍历到的某个单词,如果这个单词以前已经统计过,就把映射results中以该单词为key的映射条目的value增加1。如果以前没有被统计过,则为这个单词新创建一个映射条目,只需要直接对相应的key进行赋值,就实现了添加新的映射条目;
行17:对Map对象results进行遍历,输出统计结果。

image.png

你可能感兴趣的:(Scala入门系列之十三--针对容器的操作(遍历/映射/过滤/规约操作))