十七、Scala的Traversable集合


1. 集合

1.1 概述

很多编程语言都提供了数据结构的对应编程库,并称之为集合库(Collection Library)。Scala中也有集合库,其优点如下:

  • 易于使用:使用集合库提供的20到50个左右的方法。灵活的组合运用,能解决大部分的集合问题。
  • 简洁:简单的一个单词(如foreach)就可以实现一个或多个循环操作
  • 安全:大多错误都在编译期被发现
  • 快速:集合类型的方法实现时,都进行了调优。用户可以根据需求选择合适的集合。
  • 统一:Scala的集合有严谨的继承体系,相似类型的集合拥有同样的一组方法,以及属于自己独有的方法。

1.2 分类

Scala同时支持不可变集合和可变集合,因为不可变集合可以安全地并发访问,所以它是默认使用的集合类库。在Scala中,对于几乎所有的集合类,都提供了可变和不可变两个版本,具体如下:

  • 不可变集合:集合内的元素一旦初始化完成就不可再进行更改,任何对集合的改变都将生成一个新的集合(都在scala.collection.immutable这个包下,使用时无需手动导包)
  • 可变集合:集合本身可以动态变化,且提供了改变集合内元素的方法(都在scala.collection.mutable这个包下,使用时需手动导包)

在这里插入图片描述
在这里插入图片描述

2. Traversable

2.1 概述

Traversable是一个特质(trait),它是其他集合的父特质,它的子特质immutable.Traversable和mutable.Traversable分别是不可变集可变集合的父特质,集合中大部分通用的方法都是在这个特质中定义的。因此了解它的功能对学习其他集合类十分重要。

2.2 格式

格式一:创建空的Traversable对象

//方式一:通过empty方法实现
val t1 = Traversable.empty[Int]

//方式二:通过小括号方式实现
val t2 = Traversable[Int]()

//方式一:通过Nil实现
val t3 = Nil

格式二:创建带参数的Traversable对象

//方式一:通过toTraversable()方法实现
val t1 = List(1, 2, 3).toTraversable

//方式二:通过Traversable的伴生对象的apply()方法实现
val t2 = Traversable(123)

2.3 创建Traversable对象

需求:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.创建空的,用来存储Int类型数据的Traversable对象
		val t1:Traversable[Int] = Traversable.empty[Int]
		val t2:Traversable[Int] = Traversable[Int]()
		val t3:Traversable[Int] = Nil

		//==比较的是集合中的数据
		println(t1 == t2) //true
		println(t3 == t2) //true
		println(t1 == t3) //true

		//eq比较的是集合的地址值
		println(t1 eq t2) //true
		println(t3 eq t2) //true
		println(t1 eq t3) //true

		//2.创建Traversable集合对象,存储数字1,2,3,并将结果打印到控制台上
		val t4:Traversable[Int] = List(1,2,3).toTraversable
		val t5:Traversable[Int] = Set(1,2,3).toTraversable
		val t6:Traversable[Int] = Traversable(11,22,33,44,55)

		//打印结果  //细节:因为Traversable是一个特质,所以底层还是通过它的具体子类来实现
		println(t4) //List(1, 2, 3)
		println(t5) //Se(1, 2, 3)
		println(t6) //List(11, 22, 33, 44, 55)
	}
}

2.4 转置Traversable集合

矩阵中有一个转置的操作。Scala中,可通过transpose()方法来实现类似操作(相当于‘列变行’)。

在这里插入图片描述
注意:
进行转置操作时,程序会自动检测每个集合中的元素个数是否一致,如果一致,则转置成功;否则报错。

示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合t1,它有三个元素,每个元素都是Traversable集合
		val t1:Traversable[Traversable[Int]] = Traversable(Traversable(147), Traversable(258), Traversable(369))
		
		//2.对t1进行转置操作
		val t2:Traversable[Traversable[Int]] = t1.transpose

		//打印结果  
		println(t2)
	}
}
//List(List(1,2,3), List(4,5,6), List(7,8,9))

2.5 拼接集合

实际开发中,数据是从多渠道获取的,所以我们经常需要拼接一些数据。Scala中,我们可以通过++来拼接数据,但这种方式会创建大量的临时集合(即:每++一次,就会创建一个新的临时集合),针对这种情况,我们用concat()方法。该方法会预先计算出所需的集合的大小,然后生成一个集合,减少了中间无用的临时集合,所以更加有效。

示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义三个Traversable集合 //底层是创建list列表
		val t1 = Traversable(11,22,33)
		val t2 = Traversable(4455)
		val t3 = Traversable(66778899)
		
		//2.拼接操作
		val t4 = Traversable.concat(t1,t2,t3)

		//打印结果  
		println(t4)
	}
}
//List(11,22,33,44,55,66,77,88,99)

2.6 利用偏函数筛选元素

Scala中,可以通过collect()方法实现偏函数结合集合来使用,从而来从集合中筛选指定的数据。

格式:

def collect[B](pf:PartialFunction[A, B]):Traversable[B]

解释:

  • [B]表示通过偏函数处理后,返回值的数据类型
  • pf:PartialFunction[A, B] 表示collect()方法需要传入一个偏函数对象
  • Traversable[B]表示返回的具体数据的集合

示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合
		val t1 = (1 to 10).toTraversable //底层是Vector
		val t2 = Traversable(1,2,3,4,5,6,7,8,9,10) //底层是List

		
		//2.筛选出集合中所有的偶数
		//方式一:分解版
		val pf:PartialFunction[Int, Int] = {
			case x if x % 2 == 0 => x
		}
		val t3 = t1.collect(pf)

		//方式二:合并版
		val t4 = t2.collect({case x if x % 2 == 0 => x})

		//打印结果  
		println(t3) //Vector(2,4,6,8,10)
		println(t4) //List(2,4,6,8,10)
	}
}

2.7 计算集合元素的阶乘

假设一个Traversable[Int]集合中包含(1,2,3,4,5)五个数字,如果我们要计算每个元素的阶乘,并放到一个新的Traversable[Int]集合中,我们可以通过递归实现,但弊端是每次计算哦都需要从头开始计算。因此,我们用scan()方法来优化,它不仅将中间的计算结果放入新的集合,并把中间结果传递给下一次的函数调用。

格式:

def scan[B](z:B)(op:(B,B) => B)

解释:

  • [B]表示返回值的数据类型
  • (z:B)表示初始化值
  • (op:(B,B) => B)表示一个具体的运算函数
  • scan()方法等价于scanLeft()方法,还有一个相反的方法scanRight()

示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合
		val t1 = Traversable(1,2,3,4,5) 

		//2.分别获取t1集合中各个元素的阶乘值
		//方式一:普通写法
		val t2 = t1.scan(1)((x:Int, y:Int) => x * y)

		//方式二:合并版
		val t3 = t1.scan(2)(_ * _)

		//3.打印结果  
		println(t2) //List(1,1,2,6,24,120)
		println(t3) //List(2,2,4,12,48,240)
	}
}

2.8 获取集合的指定元素

在这里插入图片描述
示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合
		val t1 = Traversable(1,2,3,4,5,6) 

		//2.获取集合中的首尾第一个元素
		println(t1.head) //1 //如果集合为空,则报错
		println(t2.last) //6 //如果集合为空,则报错
		println(t1.headOption) //Some(1) //如果集合为空,则返回None
		println(t2.lastOption) //Some(6) //如果集合为空,则返回None

		//3.获取集合中第一个偶数
		println(t1.find(_ % 2 == 0)) //Some(2)

		//4.获取3,4,5这三个元素,并放到一个新的Traversable集合 
		val t2 = t1.slice(2,5) //包左不包右
		println(t2) //List(3,4,5)
	}
}

2.9 判断元素是否合法

如果遇到判断集合中所有的元素是否都满足指定的条件,或任意元素满足指定的条件这种需求时,就可以用forall()和exists()方法:

  • forall():如果集合中所有元素都满足指定的条件,则返回true,反则返回false

    def forall(p:(A) => Boolean):Boolean
    
  • exists():只要集合中任意一个元素满足指定的条件,则返回true,反则返回false

    def exists(p:(A) => Boolean):Boolean
    

示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合
		val t1 = Traversable(1,2,3,4,5,6) 

		//2.判断t1中的元素是否都是偶数
		println(t1.forall(_ % 2 == 0)) //false
		//还可以用filter()方法,但这里不推荐,因为该方法会返回一个集合对象
		println(t1.filter(_ % 2 != 0).size == 0) //false
		
		//3.判断t1中的元素是否有偶数
		println(t1.exists(_ % 2 == 0)) //true

	}
}

2.10 聚合函数

在这里插入图片描述
示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合
		val t1 = Traversable(1,2,3,4,5,6) 

		//2.统计t1中的奇数个数是否都是偶数
		println(t1.count(_ % 2 != 0)) //3
		//还可以用filter()方法,但这里不推荐,因为该方法会返回一个集合对象
		println(t1.filter(_ % 2 != 0).size) //3
		
		//3.获取t1中所有元素的和、乘积、最值
		println(t1.sum) //21
		println(t1.product) //720
		println(t1.max) //6
		println(t1.min) //1

	}
}

2.11 集合类型转换

有时需要把Traversable集合转换成其他的集合来进行操作,需要用到toXxx()方法 (比如toList, toSet, toArray, toSeq等)

示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.定义一个Traversable集合
		val t1 = Traversable(1,2,3,4,5) 

		//2.把t1集合转换成其他形式
		println(t1.toArray) //输出语句直接打印数组对象,打印的是地址值
		println(t1.toList)
		println(t1.toSet) 
	}
}
//[I@6537cf78
//List(1,2,3,4,5) 
//Set(1,2,3,4,5) 

2.12 填充元素

在这里插入图片描述
示例:
在这里插入图片描述

object ClassDemo {
	def main(args:Array[String]):Unit = {
		//1.
		println(Traversable.fill(5)("传智播客"))  //List(传智播客,传智播客,传智播客,传智播客,传智播客)

		//2.
		println(Traversable.fill(3)(Random.nextInt(100)))
		
		//3.
		println(Traversable.fill(5, 2)("传智播客")) //List(List(传智播客,传智播客),List(传智播客,传智播客),List(传智播客,传智播客),List(传智播客,传智播客),List(传智播客,传智播客))

		//4.
		println(Traversable.iterate(1, 5)(_ * 10)) //List(1,10,100,1000,10000)

		//5.
		println(Traversable.iterate(1,21,5)) //List(1,6,11,16)
	}
}

3. 案例:随机学生序列

需求:
在这里插入图片描述
步骤:
在这里插入图片描述

object ClassDemo {
	//1.创建Student样例类,用来记录学生信息
	case class Student(name:String, age:Int)

	def main(args:Array[String]):Unit = {
		//2.定义列表,记录学生的姓名信息
		val names:List[String] = List("张三", "李四", "王五", "赵六", "田七")
		//3.创建随机数对象r,用来实现获取一些随机值的操作
		val r:Random = new Random()
		//4.创建Traversable集合,包含5个随机的学生信息
		val t1:Traversable[Student] = Traversable.fill(5)(new Student(names(r.nextInt(names.size)),r.nextInt(10) + 20))
		//5.将Traversable集合转换成列表
		val t2:List[Student] = t1.toList
		//6.通过列表的sortWith()方法,按照学生的年龄降序排列
		//思路一:通过sortBy()方法实现
		val sortList:List[Student] = t2.sortBy(_.age).reverse
		//思路二:通过sortWith()方法实现
		val sortList:List[Student] = t2.sortWith(_.age > _.age)


		//7.打印结果
		println(sortList) //List(Student(田七,27), Student(田七,27), Student(王五,25), Student(张三,25), Student(田七,21))
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值