1. Scala的集合体系结构
Scala中的集合体系主要包括(结构跟Java相似):
- Iterable(所有集合trait的根trait)
- Seq(Range、ArrayBuffer、List等)
- Set(HashSet、LinkedHashSet、SortedSet等)
- Map (HashMap、SortedMap、LinkedHashMap等)
Scala中的集合分为可变和不可变两类集合,分别对应scala.collection.mutable和scala.collection.immutable两个包。
2. List
List代表一个不可变的列表。
- List有head和tail,head代表List的第一个元素,tail代表第一个元素之后的所有元素。
scala> val list = List(1, 2, 3, 4) list: List[Int] = List(1, 2, 3, 4) scala> list.head res33: Int = 1 scala> list.tail res34: List[Int] = List(2, 3, 4)
案例:用递归函数给List中每个元素都加上指定的前缀并打印
// 如果List只有一个元素,那么他的tail就是Nil def decorator(list: List[Int], prefix: String){ if (list != Nil) { println(prefix + list.head) decorator(list.tail, prefix) } } scala> decorator(list, "+") +1 +2 +3 +4
- List有特殊的
::
操作符,可以用于将head和tail合并成一个List。
scala> list res37: List[Int] = List(1, 2, 3, 4) scala> 0::list res38: List[Int] = List(0, 1, 2, 3, 4)
该操作符在Spark源码中有体现
3. LinkedList
LinkedList代表一个可变的列表,其elem和next属性类似于List的head和tail。
案例:使用while循环将LinkedList中每个一个元素乘以二。
val list = scala.collection.mutable.LinkedList(1,2,3,4,5,6,7,8,9) var currentList = list var first = true while( currentList !=Nil && currentList.next != Nil){ if(first) { currentList.elem *= 2; first = false} currentList = currentList.next.next if(currentList != Nil) currentList.elem *= 2 } list: scala.collection.mutable.LinkedList[Int] = LinkedList(2, 2, 6, 4, 10, 6, 14, 8, 18)
4. Set
Set代表一个没有重复元素的集合
HashSet
不保证插入顺序,元素是乱序的
scala> val s = new scala.collection.mutable.HashSet[Int]() s: scala.collection.mutable.HashSet[Int] = Set() scala> s += 1 res40: s.type = Set(1) scala> s += 2 res41: s.type = Set(1, 2) scala> s += 5 res42: s.type = Set(1, 5, 2)
LinkedHashSet
保证插入顺序,底层使用链表
scala> val s = new scala.collection.mutable.LinkedHashSet[Int]() s: scala.collection.mutable.LinkedHashSet[Int] = Set() scala> s += 1 res43: s.type = Set(1) scala> s += 2 res44: s.type = Set(1, 2) scala> s += 5 res45: s.type = Set(1, 2, 5)
SortedSet
会自动根据key来进行排序(默认字母顺序)
scala> val s = scala.collection.mutable.SortedSet("orange", "apple", "banana") s: scala.collection.mutable.SortedSet[String] = TreeSet(apple, banana, orange)
5. 集合的函数式编程(重要!)
Scala中集合的函数式编程最大的体现就是对于一系列高阶函数的使用。
高阶函数的使用是Scala与Java最大的区别!因为Java中没有函数式编程,也肯定没有高阶函数,无法直接将函数传入一个方法,或者让一个方法返回一个函数。
// 为List中的每个元素都添加一个前缀 scala> List("leo", "spark","peter").map("name is " + _) res47: List[String] = List(name is leo, name is spark, name is peter) // 拆分单词 scala> List("Hello world", "your are my friend").flatMap(_.split(" ")) res48: List[String] = List(Hello, world, your, are, my, friend) // 打印每一个元素 scala> List("Hello world", "your are my friend").foreach(println(_)) Hello world your are my friend // 学生姓名和成绩进行关联 scala> List("leo", "jen", "jack").zip(List(100, 30, 20)) res50: List[(String, Int)] = List((leo,100), (jen,30), (jack,20))
6. 综合案例:统计多个文本内的单词总数
// 使用scala的IO包将文件文件内的数据读取出来 scala> val lines1 = scala.io.Source.fromFile("E://test.txt").mkString lines1: String = hello my scala> val lines2 = scala.io.Source.fromFile("E://test2.txt").mkString lines2: String = you are a good boy // 使用List的伴生对象,将多个文件内的内容创建为一个List scala> val lines = List(lines1, lines2) lines: List[String] = List(hello my, you are a good boy) // 首先将所有元素以空格分割单词,接着将每个单词映射为(单词,1)元组, 然后再取出元组里的第二个元素(_._2表示取出元组中的第二个元素),最后做累加 scala> lines.flatMap(_.split(" ")).map((_, 1)).map(_._2).reduceLeft(_ + _) res51: Int = 7
注意:最后一行多个高阶函数的链式调用其实就是Scala函数式编程的精髓所在,也是Scala相较于Java等编程语言最大的功能优势所在。并且Spark的源码中大量使用了这种复杂的链式调用,Spark本身提供的开发API也完全沿用了Scala的函数式编程。