Scala笔记整理(六):Scala集合库
[TOC]
Scala主要集合结构
1、Scala中的集合体系主要包括:Iterable
、Seq(IndexSeq)
、Set(SortedSet)
、Map(SortedMap)
。其中Iterable是所有集合trait的根trait。实际上Seq、Set、和Map都是子trait
Seq
是一个有先后次序的值的序列,比如数组或列表。IndexSeq允许我们通过×××的下表快速的访问任意元素。举例来说,ArrayBuffer是带下标的,但是链表不是。
Set
是一组没有先后次序的值。在SortedSet中,元素以某种排过序顺序被访问。
Map
是一组(键、值)对偶。SortedMap按照键的排序访问其中的实体。
2、 Scala中的集合是分成可变和不可变两类集合的,其中可变集合就是说,集合的元素可以动态修改,而不可变集合的元素在初始化之后,就无法修改了。分别对应scala.collection.mutable
和scala.collection.immutable
两个包。
3、Seq下包含了Range
、ArrayBuffer
、List
等子trait。其中Range就代表了一个序列,通常可以使用"1 to10"这种语法来产生一个Range。 ArrayBuffer就类似于Java中的ArrayList。
List
List常用操作1
1、在Scala中,列表要么是Nil(及空表),要么是一个head元素加上一个tail,而tail又是一个列表
scala> val list = List(1, 2, 3, 4, 5)list: List[Int] = List(1, 2, 3, 4, 5)scala> list.headres29: Int = 1scala> list.tailres30: List[Int] = List(2, 3, 4, 5)scala> list.isEmptyres31: Boolean = falsescala> list == Nilres32: Boolean = false
下面是一个使用递归求list集合中和的例子:
def recursion(list:List[Int]):Int = { if(list.isEmpty) { return 0 // 使用return显式结束程序的运行,否则0只是该if语句的返回值,并不会结束程序的运行,当然如果用else不用return也行 } list.head + recursion(list.tail)}
List常用操作2
增加
//增/* A.++(B) --> 在列表A的尾部对添加另外一个列表B,组成一个新的列表 * A.++:(B) --> 在列表A的首部对添加另外一个列表B,组成一个新的列表 * A.:::(B) --> 在列表A的首部对添加另外一个列表B,组成一个新的列表 * ------ * A.:+ (element) -->在列表A的尾部添加一个element,组成一个新的集合 * A.+: (element) -->在列表A的首部添加一个element,组成一个新的集合 * A.:: (element) -->在列表A的首部添加一个element,组成一个新的集合 */
测试如下:
scala> val left = List(1, 2, 3, 4)left: List[Int] = List(1, 2, 3, 4)scala> val right = List(5, 6, 7)right: List[Int] = List(5, 6, 7)scala> left.++(right)res33: List[Int] = List(1, 2, 3, 4, 5, 6, 7)scala> left.++:(right)res34: List[Int] = List(5, 6, 7, 1, 2, 3, 4)scala> left.:::(right)res35: List[Int] = List(5, 6, 7, 1, 2, 3, 4)scala> left.:+(10)res36: List[Int] = List(1, 2, 3, 4, 10)scala> left.+:(10)res38: List[Int] = List(10, 1, 2, 3, 4)scala> left.::(10)res39: List[Int] = List(10, 1, 2, 3, 4)
删除
drop(n) --->删除list的前n个元素(首部开始删除)dropRight(n) --->删除list的后n个元素(尾部开始删除)dropWhile(p: A => Boolean) --->逐个匹配去除符合条件的元素,直到不符合条件,之后的元素不再判断
测试如下:
scala> val list = List(1, 2, 3, 4, 5, 6, 7)list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)scala> list.drop(2)res52: List[Int] = List(3, 4, 5, 6, 7)scala> list.dropRight(3)res53: List[Int] = List(1, 2, 3, 4)scala> list.dropWhile(_ <= 3)res54: List[Int] = List(4, 5, 6, 7)scala> list.dropWhile(_ > 3) // 第一个元素就不符合条件,后面的不再判断,所以一个也没有删除res55: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
修改与查询
scala> val list = List(1, 2, 3, 4, 5, 6, 7)list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)scala> list(0)res57: Int = 1scala> list(0) = 10:9: error: value update is not a member of List[Int] list(0) = 10 ^
默认的List是在:
scala> Listres59: scala.collection.immutable.List.type = scala.collection.immutable.List$@3e98fd35
所以不能修改,但是尝试导入可修改的List也不能进行导入:
scala> import scala.collection.mutable.List:8: error: object List is not a member of package scala.collection.mutable import scala.collection.mutable.List
原因如下:
Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。
List常用操作3
scala> val list = List(1, 2, 3, 4, 5, 6, 7)list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)scala> list.take(5)res60: List[Int] = List(1, 2, 3, 4, 5)scala> list.takeWhile(_ <= 3)res61: List[Int] = List(1, 2, 3)scala> list.takeWhile(_ > 3)res62: List[Int] = List()scala> list.mkStringres63: String = 1234567scala> list.count(_ % 2 == 0)res64: Int = 3scala> val fruit = "apples" :: ("oranges" :: ("pears" :: Nil)) // ::操作符从给定的头和尾部创建一个新的列表fruit: List[String] = List(apples, oranges, pears)scala> val list1 = List(1, 2, 3)list1: List[Int] = List(1, 2, 3)scala> val list2 = List(4, 5, 6)list2: List[Int] = List(4, 5, 6)scala> list1 ++ list2 // ++两个集合之间的操作res70: List[Int] = List(1, 2, 3, 4, 5, 6)scala> list1.sumres72: Int = 6
Set
1、数据集是不重复元素的集合。尝试将已有元素加入进来是没有效果的。比如
def setOps:Unit ={ (Set(2,0,1) + 1).foreach(println(_))}
2、Set不保留元素插入的顺序。缺省情况下,集是以哈希集实现的,其元素根据hashCode方法的值进行组织。
Set(1,2,3,5,7,8).foreach(println(_))
3、链式哈希集可以记住元素被插入的顺序。它会维护一个链表来达到这个目的。
val weeks= scala.collection.mutable.LinkedHashSet("Mo","Tu","We","Th","Fr")weeks.foreach(println(_))
4、按照已排序的顺序来访问其中的元素
scala.collection.immutable.SortedSet(1,2,3,4,5,6).foreach(println(_))
set集合顺序说明
直接看下面的测试代码及注释:
package cn.xpleaf.bigdata.p4.collectionimport scala.collection.mutable.SortedSetobject _02CollectionOps { def main(args: Array[String]): Unit = { setOps1 } /** * 关于scala集合顺序的说明 * 测试1:按照年龄进行升序,年龄相等,姓名降序 * 测试2:要按照姓名升序比较,按照年龄升序比较 * SortedSet在添加普通对象Person之类,报错 * No implicit Ordering defined for Person * 要想在有序集合中添加元素,必须要让元素具备比较性,要和给集合提供比较器 * 在java中前者是要类实现Comparator,后者需要给集合提供一个比较器Comparator * 在scala中,前者需要让类扩展Ordered的特质,后者给集合传递一个Ordering比较器 * * 当两个比较都实现的话,优先使用集合的比较器 */ def setOps1: Unit = { var set = SortedSet[Person]()(new Ordering[Person] { override def compare(x: Person, y: Person):Int = { var ret = x.getName.compareTo(y.getName) if(ret == 0) { ret = x.getAge.compareTo((y.getAge)) } ret } }) set.+= (new Person("王立鹏", 19)) set.+= (new Person("冯 剑", 18)) set.+= (new Person("刘银鹏", 15)) set.+= (new Person("李小小", 19)) // println(set) set.foreach(println(_)) }}class Person extends Ordered[Person] { private var name:String = _ private var age:Int = _ def this(name:String, age:Int) { this() this.name = name this.age = age } def getAge = age def getName = name override def toString: String = { s"[$name, $age]" } /** * 按照年龄进行升序,年龄相等,姓名降序 * 升序:前面比后面 * 降序:后面比前面 */ override def compare(that: Person) = { var ret = this.age.compareTo(that.age) if(ret == 0) { ret = that.name.compareTo(this.name) } ret }}
输出结果如下:
[冯 剑, 18][刘银鹏, 15][李小小, 19][王立鹏, 19]
集合的函数式编程
1、集合的函数式编程非常之重要,这是我们以后工作中每天都在使用的编程方式。
2、必须完全掌握和理解Scala的高阶函数是什么意思,Scala的集合类的map、flatMap、reduce、reduceLeft、foreach等这些函数,就是高阶函数,因为可以接收其他函数作为参数(部分高阶函数可以参考前面整理的函数式编程笔记)
3、高阶函数的使用,也是Scala与Java最大的一点不同!!!因为Java在1.8之前是没有函数式编程的,也肯定没有高阶函数,也肯定无法直接将函数传入一个方法,或者让一个方法返回一个函数
4、对Scala高阶函数的理解、掌握和使用,可以大大增强你的技术,而且也是Scala最有诱惑力、最有优势的一个功能。
5、在Spark源码中,有大量的函数式编程,所以必须掌握,才能看懂spark源码。
- foreach方法可以将某个函数应用到集合中的每个元素并产生结果的集合
scala> val names = List("Peter","Paul","Mary")names: List[String] = List(Peter, Paul, Mary)scala> names.map(_.toUpperCase).foreach(println(_))PETERPAULMARY
- Map函数每个后面都加上一个==》
scala> List("Peter","Paul","Mary").map(_ + "===>name").foreach(println(_))Peter===>namePaul===>nameMary===>name
- Flatmap按照空格进行划分
scala> List("Peter Glad","Paul Hello","Mary Your").flatMap(_.split(" ")).foreach(println)PeterGladPaulHelloMaryYour