数组是用来存储多个同类型元素的容器。每个元素都有编号/下标/脚标/索引,且编号都是从0开始数的。
特点:
语法:
格式一:通过指定长度定义数组
val/var 变量名 = new Array[元素类型](数组长度)
格式二:通过指定元素定义数组
val/var 变量名 = new Array(元素1, 元素2, 元素3...)
注意:
[]
来指定数组名(索引)
来获取数组中的元素数组名.length
或数组名.size
来获取数组的长度object ClassDemo {
def main(args: Array[String]):Unit = {
//1
var arr1 = new Array[Int](10)
arr1(0) = 11
println(arr1(0))
//2
var arr2 = Array("java", "scala", "python")
println(arr2.length)
println(arr2.size)
}
}
//1
//3
//3
特点:
数组的长度和内容都是可变的,可以往数组中添加、删除元素
语法:
创建变长数组,需要先导入ArrayBuffer类
import scala.collection.mutable.ArrayBuffer
定义格式一:创建空的ArrayBuffer变长数组
val/var 变量名 = ArrayBuffer[元素名称]()
定义格式二:创建带有初始元素的ArrayBuffer变长数组
val/var 变量名 = ArrayBuffer(元素1, 元素2, 元素3...)
import scala.collection.mutable.ArrayBuffer
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
var arr1 = ArrayBuffer[Int]()
//2
var arr2 = ArrayBuffer("hadoop", "storm", "spark")
//3
println(arr1)
println(arr2)
}
}
//ArrayBuffer()
//ArrayBuffer(hadoop, storm, spark)
示例二:增删改元素
格式:
使用+=
添加单个元素
使用-=
删除单个元素
使用++=
追加一个数组到变长数组中
使用--=
移除变长数组中的指定多个元素
import scala.collection.mutable.ArrayBuffer
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
var arr1 = ArrayBuffer("hadoop", "spark", "flink")
//2
arr1 += "flume"
//3
arr11 -= "hadoop"
//4
arr1 ++= Array("hive", "sqoop")
//5
arr1 --= Array("sqoop", "spark")
//6
println(arr1)
}
}
//ArrayBuffer(flink, flume, hive)
Scala中,可以使用以下两种方式遍历数组:
索引
遍历数组中的元素for表达式
直接遍历数组中的元素object ClassDemo {
def main(args: Array[String]):Unit = {
//1
var arr = ArrayBuffer(1, 2, 3, 4, 5)
//2
//方式一:通过索引实现
//i:数组中每个元素的索引 to:包左也包右
for(i <- 0 to arr1.length - 1) println(arr1(i))
println("-" * 15)
//i:数组中每个元素的索引 until:包左不包右
for(i <- 0 until arr1.length) println(arr1(i))
println("-" * 15)
//方式二:直接获取元素
//i:数组中的每个元素
for(i <- arr1) println(i)
}
}
//1
//2
//3
//4
//5
//---------------
//1
//2
//3
//4
//5
//---------------
//1
//2
//3
//4
//5
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val arr = Array(4, 1, 6, 5, 2, 3)
//2
println(arr.sum)
println(arr.max)
println(arr.min)
val arr2 = arr.sorted
val arr3 = arr.reverse
//3.打印结果
for(i <- arr) println(i) //4,1,6,5,2,3
for(i <- arr2) println(i) //1,2,3,4,5,6
for(i <- arr3) println(i) //3,2,5,6,1,4
}
}
//21
//6
//1
//剩余结果已写在注释
元组一般用来存储多个不同类型的值。且元组的长度和元素都是不可变的。
格式一:通过小括号实现
val/var 元组 = (元素1, 元素2, 元素3...)
格式二:通过箭头实现(只适合于元组中只有两个元素的情况)
val/var 元组 = 元素1->元素2
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.通过小括号形式实现
val tup1 = ("lee", 23)
//2.通过箭头方式实现
val tup2 = "mike" -> 24
//3.打印结果
println(tup1)
println(tup2)
}
}
//(lee,23)
//(mike,24)
Scala中,可以通过元组名._编号
的形式来访问元组中的元素,_1表示访问第一个元素,以此类推;也可以通过元组名.productIterator
的方式,来获取该元组的迭代器,从而实现遍历元组
格式一:访问元组中的单个元组
println(元组名._1) //打印元组的第一个元素
println(元组名._2) //打印元组的第二个元素
...
格式二:遍历元组
val tuple1 = (值1, 值2, 值3...) //可以有多个值
val it = tuple1.productIterator //获取当前元组的迭代器对象
for(i <- it) println(i)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val tup1 = "lee" -> "male"
//2.
//方式一:通过_编号获取,编号是从1开始技术的
println(tup1._1)
println(tup1._2)
//方式二:通过迭代器遍历
val it = tup1.prodcutIterator
for(i < it) println(i)
}
}
//lee
//male
//lee
//male
列表是Scala最重要也是最常用的一种数据结构,它存储的数据的特点是:有序,可重复。
Scala中列表分为不可变列表和可变列表。
不可表列表的元素、长度都是不可变的。
语法:
格式一:通过小括号直接初始化
val/var 变量名 = List(元素1, 元素2, 元素3...)
格式二:通过Nil创建一个空列表
val/var 变量名 = Nil
格式三:使用::方法实现 (必须在最后添加一个Nil)
val/var 变量名 = 元素1 :: 元素2 :: Nil
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val list1 = List(1, 2, 3, 4)
//2.
val list2 = Nil
//3.
val list3 = -2::-1::Nil
//4.打印结果
println(list1)
println(list2)
println(list3)
}
}
//List(1, 2, 3, 4)
//List()
//List(-2, -1)
可变列表的元素、长度都是可变的。
语法:
要使用可变列表,必须先导包
(技巧:可变集合都在mutable
包中,不可变集合都在immutable
包中(默认))
import scala.collection.mutable.ListBuffer
格式一:创建空的可变列表
val/var 变量名 = ListBuffer[数据类型]()
格式二:通过小括号
直接初始化
val/var 变量名 = ListBuffer(元素1, 元素2, 元素3...)
import scala.collection.mutable.ListBuffer
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val list1 = ListBuffer[Int]()
//2.
val list2 = ListBuffer(1, 2, 3, 4)
//3.打印结果
println(list1)
println(list2)
}
}
//ListBuffer()
//ListBuffer(1, 2, 3, 4)
import scala.collection.mutable.ListBuffer
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val list1 = ListBuffer(1, 2, 3)
//2.
println(list1(0))
//3.
list1 += 4
//4.
list1 ++= List(5, 6, 7)
//5.
list1 -= 7
//6.
list1 --= List(3, 4)
//7.
val list2 = list1.toList
//8.
val arr = list1.toArray
//9.打印结果
println(list1) //ListBuffer(1, 2, 5, 6)
println(list2) //List(1, 2, 5, 6)
println(arr) //[I@4411d970 //输出语句直接打印数组,打印的是数组的地址值
}
}
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val list1 = List(1, 2, 3, 4)
//2.
println(list1.isEmpty) //false
//3.
val list2 = List(4, 5, 6)
//4.
val list3 = list1 ++ list2
println(list3) //List(1, 2, 3, 4, 4, 5, 6)
//5.
println(list1.head) //1
//6.
println(list.tail) //List(2, 3, 4)
//7.
println(list1.reverse) //List(4, 3, 2, 1)
//8.这里的3表示:前3个元素都是前缀元素
println(list1.take(3)) //List(1, 2, 3)
//9.这里的3表示:除了前3个是前缀元素外,剩下都是后缀元素
println(list1.drop(3)) //List(4)
}
}
示例二:扁平化(压平)
扁平化表示嵌套列表中的所有具体元素单独的放到一个新列表中(如果某个列表中的所有元素都是列表,那么这样的列表称为嵌套列表)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val list1 = List(List(1, 2), List(3), List(4, 5))
//2.
val list2 = list1.flatten
//3.
println(list1) //List(List(1, 2), List(3), List(4, 5))
println(list2) //List(1, 2, 3, 4, 5)
}
}
示例三:拉链与拉开
拉链:将两个列表,组合成一个元素为元组的列表
拉开:将一个包含元组的列表,拆解成包含两个列表的元组
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val names = List("张三", "李四", "王五")
//2.
val ages = List(23, 24, 25)
//3.
val list1 = names.zip(ages) //List(("张三", 23),("李四", 24),("王五", 25))
//4.
val tuple1 = list1.unzip //(List("张三", "李四", "王五"), List(23, 24, 25))
}
}
示例四:列表转字符串
将列表转换成其对应的字符串形式,可以通过toString方法或者mkString方法实习,其中
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.
val list1 = List(1, 2, 3, 4)
//2.
println(list1.toString) //List(1, 2, 3, 4)
//简写形式,如果输出语句打印的是对象,默认会调用对象的toString()方法
println(list1) //List(1, 2, 3, 4)
//3.
println(list1.mkString) //1234
println(list1.mkString(":")) //1:2:3:4
}
}
示例五:并集、交集、差集
l1.union(l2)
表示获取l1和l2所有的元素(不去重)
distinct
实现l1.intersect(l2)
表示获取l1,l2都有的元素l1.diff(l2)
表示获取l1中有,但l2中没有的元素object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val list1 = List(1, 2, 3, 4)
//2
val list2 = List(3, 4, 5, 6)
//3
val unionList = list1.union(list2) //List(1, 2, 3, 4, 3, 4, 5, 6)
//4
val distinctList = unionList.distinct //List(1, 2, 3, 4, 5, 6)
//5
val intersectList = list1.intersect(list2) //List(3, 4)
//6
val diffList = list1.diff(list2) //List(1, 2)
}
}
集代表没有重复的集合,特点是:唯一,无序
Scala中的集分为不可变集(和可变集
不可变集的元素、长度都不可变
语法:
格式一:创建一个空的不可变集
val/var 变量名 = Set[类型]()
格式二:给定元素来创建一个不可变集
val/var 变量名 = Set(元素1, 元素2, 元素3...)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val set1 = Set[]()
//2
val set2 = Set(1, 1, 3, 2, 4, 8)
//3
println(set1) //Set()
println(set2) //Set(1, 2, 3, 8, 4)
}
}
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val set1 = Set(1, 1, 3, 2, 4, 5)
//2
println(set1.size) //5
//3
for(i <- set1) println(i) // 5 1 2 3 4
//4
val set2 = set1 - 1
println(set2) //Set(5, 2, 3, 4)
//5
val set3 = set1 ++ Set(6,7,8)
println(set3) //Set(5, 1, 6, 2, 7, 3, 8, 4)
//6
val set4 = set1 ++ List(6,7,8,9)
println(set4) //Set(5, 1, 6, 9, 2, 7, 3, 8, 4)
}
}
可变集的元素、长度都可变,它的创建方式和不可变集的创建方式一致,只不过需要先导入可变集类
手动导入:import scala.collection.mutable.Set
import scala.collection.mutable.Set
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val set1 = Set(1, 2, 3, 4)
//2
set1 += 5 //Set(1, 5, 2, 3, 4)
//3
//方式一:set1 ++= Set(6, 7, 8)
//方式二:
set1 ++= List(6, 7, 8) //Set(1, 5, 2, 6, 3, 7, 4, 8)
//4
set1 -= 1 //Set(5, 2, 6, 3, 7, 4, 8)
//5
//方式一:set1 --= Set(3, 5, 7)
//方式二:
set1 --= List(3, 5, 7) //Set(2, 6, 4, 8)
}
}
映射(Map)是由键值对(key, value)组成的集合,特点是键具有唯一性,但是值可以重复
Scala中可以分为不可变Map和可变Map
不可变Map的元素、长度都不可变
语法:
方式一:通过箭头
的方式实现
val/var map = Map(键 -> 值, 键 -> 值, 键 -> 值...) //推荐,可读性更好
方式二:通过小括号
的方式实现
val/var map = Map((键,值), (键,值), (键,值)...)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
//方式一
val map1 = Map("张三" -> 23, "李四" -> 24, "李四" -> 40)
//方式二
val map2 = Map(("张三", 23), ("李四", 24), ("李四", 40))
//2
println(map1) //Map(张三 -> 23, 李四 -> 40)
println(map2) //Map(张三 -> 23, 李四 -> 40)
}
}
可变Map的元素、长度都可变,定义语法与不可变Map一致,只不过需要先手动导包: import scala.collection.mutable.Map
import scala.collection.mutable.Map`
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
//方式一
val map1 = Map("张三" -> 23, "李四" -> 24)
//方式二
val map2 = Map(("张三", 23), ("李四", 24))
//2
map1("张三") = 30
//3
println(map1) //Map(张三 -> 30, 李四 -> 24
println(map2) //Map(张三 -> 23, 李四 -> 24)
}
}
import scala.collection.mutable.Map`
object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val map1 = Map("张三" -> 23, "李四" -> 24)
//2
println(map1("张三")) //23
//3
println(map1.keys) //Set(张三,李四)
//4
println(map1.values) //MapLike(23, 24)
//5
for((k, v) <- map1) println(k, v)
//6
println(map1.getOrElse("王五", -1)) //-1
//7
//val map2 = map1 + "王五" -> 25
//println(map2) //(Map(张三 -> 23, 李四 -> 24)王五,25))
map1 += "王五" -> 25
println(map1) //Map(王五 -> 25, 张三 -> 23, 李四 -> 24)
//8
map -= "李四" //根据键删除相应的键值对 //Map(王五 -> 25, 张三 -> 23)
}
}
Scala针对每一类集合都提供了一个迭代器(iterator),用来迭代访问集合
注意:
iterator
从集合获取迭代器
hasNext
方法: 查询容器是否有下一个元素next
方法:返回迭代器的下一个元素,没有则会抛出NoSuchElementException
NoSuchElementException
)object ClassDemo {
def main(args: Array[String]):Unit = {
//1
val list1 = List(1, 2, 3, 4, 5)
//2
//2.1通过集合对象获取其对应的迭代器对象
val it = list1.iterator
//2.2判断迭代器中是否有下一个元素
while (it.hasNext) {
//2.3如果有,则获取元素,并打印
println(it.next())
}
//当迭代器使用完毕后,再次通过next()方法获取元素
println(it.next()) //抛出异常NoSuchElementException
}
}
//1
//2
//3
//4
//5
函数式编程指定就是方法的参数列表可以接收函数对象
例如:add(10,20)不是函数式编程,而add(函数对象)这种格式就是函数式编程
将来编写Spark/Flink的大量业务代码时,都会使用到函数式编程
格式:
def foreach(f:(A) => Unit) : Unit
//简写形式
def foreach(函数)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = List(1, 2, 3, 4)
//2.使用foreach方法遍历打印每个元素
//函数的格式: (函数的参数列表) => {函数体}
//x表示: 列表list1中的每一个元素
list1.foreach((x:Int) => {println(x)})
//简写版本:
list1.foreach(x => println(x))
}
}
//1
//2
//3
//4
方式一:通过类型判断
来简化函数定义
方式二:通过下划线
来简化函数定义
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = List(1, 2, 3, 4)
//2.使用foreach方法遍历打印每个元素
//普通写法:
list1.foreach((x:Int) => {println(x)})
//使用类型推断来简化函数定义:
list1.foreach(x => println(x))
//使用下划线来简化函数定义
list1.foreach(println(_))
}
}
//1
//2
//3
//4
集合的映射操作是指将一种数据类型转换成另一种数据类型的过程,它是在进行数据计算是,甚至将来写Spark/Flink程序时用得最多的操作
例如:把List[Int]转换成List[String]
格式:
def map[B](f: (A) => B): TraversableOnce[B]
//简写形式
def map(函数对象)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = List(1, 2, 3, 4)
//2.将上述的数字转换成相应个数的'*'
//普通写法:
val list2 = list1.map((x:Int) => {"*" * x})
//使用类型推断来简化函数定义:
val list2 = list1.map(a => "*" * a)
//使用下划线来简化函数定义
val list2 = list1.map("*" * _)
println(list2)
}
}
//List(*, **, ***, ****)
扁平化映射可以理解为先map(将列表中的元素转换为一个List),后flatten。
格式:
def flatMap[B](f:(A)) => GenTraversableOnce[B]):TraversableOnce[B]
//简写形式
def flatMap(f:(A) => 要将元素A转换成的集合B的列表)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个包含了若干个文本行的列表
val list1 = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
//2.获取到文本行中的每一个单词,并将每一个单词都放到列表中
//方式一:先mao,然后flatten
val list2 = list1.map((x:String) => {x.split(" ")})
println(list2) //List(Array(),Array())
val list3 = list2.flatten
println(list3) //List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
//方式二:直接通过flatMap方法实现
//val list4 = list1.flatMap((x:String) => {x.split(" ")})
//简化:
val list4 = list1.flatMap(_.split(" "))
println(list4) //List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
}
}
过滤指的是过滤出(筛选出)符合一定条件的元素
格式:
def filter(f:(A) => Boolean):TraversableOnce[A]
//简写形式:
def filter(f:(A) => 筛选条件)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个数字列表
//val list1 = List(1,2,3,4,5,6,7,8,9)
val list1 = (1 to 9).toList
//2.过滤除所有的偶数
//val list2 = list1.filter(x => x % 2 == 0)
//简洁:
val list2 = list1.filter(_ % 2 == 0)
println(list2) //List(2, 4, 6, 8)
}
}
默认排序指的是对列表元素按照升序进行排列。如果需要降序排列,则升序后再通过reverse实现
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个数字列表
val list1 = List(3,1,2,9,7)
//2.对列表进行升序排列
val list2 = list1.sorted
println(list2) //List(1, 2, 3, 7, 9)
//3.对列表进行降序排列
val list3 = list2.reverse
println(list3) //List(9, 7, 3, 2, 1)
}
}
指定字段排序指的是对列表元素根据传入的函数转换后,再进行排序(例如:根据列表List(“01 hadoop”, “02 flume”)的字母进行排序)
格式:
def sortBy[B](f:(A) => B):List[A]
//简写形式
def sortBy(函数对象)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = List("01 hadoop", "02 flume", "03 hive", "04 spark")
//2.按照单词字母进行排序
//x表示:list1列表中的每个元素 "01 hadoop", "02 flume"
//x.split(" ")表示: Array("01", "hadoop"), Array("02", "flume")
//x.split(" ")(1)表示:"hadoop", "flume"
val list2 = list1.sortBy(x => x.split(" ")(1))
println(list2) //List(02 flume, 01 hadoop, 03 hive, 04 spark)
}
}
自定义排序指的是根据一个自定义的函数(规则)来进行排序
格式:
def sortWith(f:(A, A) => Boolean):List[A]
//简写形式
def sortWith(函数对象:表示自定义的比较规则)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = List(2, 3, 1, 6, 4, 5)
//2.使用sortWith对列表进行降序排列
//x表示:前边的元素
//y表示:后边的元素
//val list2 = list1.sortWith((x, y) => x > y)
//简练:
//第一个下划线_相当于上边的x
//第二个下划线_相当于上边的y
val list2 = list1.sortWith(_ > _)
println(list2) //List(6, 5, 4, 3, 2, 1)
}
}
分组指的是将数据按照指定条件进行分组,从而方便我们对数据进行统计分析
格式:
def groupBy[K](f:(A) => K):List[A]
//简写形式
def gourpBy(f:(A) => 具体的分组代码)
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = List("刘德华" -> "男", "刘亦菲" -> "女", "胡歌" -> "男")
//2.按照性别进行分组
//x表示列表list1中的每个元素 "刘德华" -> "男"
//x._2表示获取的是性别 "男"
//val map1 = list1.groupBy(x => x._2)
//简练:
val map1 = list1.groupBy(_ => _._2)
println(map1)//Map(男 -> List(刘德华 -> 男, 胡歌 -> 男), 女 -> List(刘亦菲 -> 女))
//3.统计不同性别的学生人数
//x表示map1中的每个元素 男 -> List(刘德华 -> 男, 胡歌 -> 男)
//x._1表示性别 "男"
//x._2表示符合条件的所有数据 "男" 对应 List(刘德华 -> 男, 胡歌 -> 男)
val map2 = map1.map(x => x._1 -> x._2.size)
println(map2) //List(男 -> 2, 女 -> 1)
}
}
聚合操作指的是将一个列表中的数据合并为一个,常用来统计分析中
reduce表示将列表传入一个函数进行聚合计算
格式:
def reduce[A1 >: A](op:(A1, A1) => A1):A1
//简写形式
def reduce(op:(A1, A1) => A1)
示例:
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = (1 to 10).toList
//2.使用reduce计算所有元素的和
//x表示聚合后的操作结果
//y表示后一个元素
//val list2 = list1.reduce((x, y) => x + y)
//简练:第一个下划线相当于上边的x,第二个下划线相当于上边的y
val list2 = list1.reduce(_ + _)
println(list2)//55
val list3 = list1.reduceLeft(_ + _)
println(list3)//55
val list4 = list1.reduceRight(_ + _)
println(list4)//55
//如果是相减操作,则reduceLeft和reduceRight得到的结果不一样
println(list1.reduce(_ - _)) //-53
println(list1.reduceRight(_ - _)) //-5
}
}
fold与reduce很像,只不过多了一个指定初始值参数
格式:
def fold[A1 >: A](z: A1)(op:(A1, A1) => A1):A1
//简写形式
def (初始值)(op:(A1, A1) => A1)
注意:
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.有一个列表
val list1 = (1 to 10).toList
//2.使用fold计算所有元素的和
//100表示初始化值
//(x,y) => x + y 表示函数对象
val list2 = list1.fold(100)((x, y) => x + y)
//简练:第一个下划线相当于上边的x,第二个下划线相当于上边的y
val list2 = list1.fold(100)(_ + _)
println(list2)//155
val list3 = list1.foldLeft(100)(_ + _)
println(list3)//155
val list4 = list1.foldRight(100)(_ + _)
println(list4)//155
}
}
object ClassDemo {
def main(args: Array[String]):Unit = {
//1.定义列表,记录学生成绩
val stuList = List(("张三",37,90,100),("李四",90,73,81),("王五",60,90,76),("赵六",59,21,72),("田七",100,100,100),)
//2.获取所有语文成绩在60分以上的同学信息
//val chineseList = stuList.filter(x => x._2 >= 60)
//简化:
val chineseList = stuList.filter(_ => _._2 >= 60)
//3.获取所有学生的总成绩
val countList = stuList.map(x => x._1 -> (x._2 + x._3 + x._4)) //这里不能用下划线简化,因为x出现了四次了
//4.按照总成绩降序排列
//val sortList = countList.sortWith((x, y) => x._2 > y._2)
//简化:
val sortList = countList.sortWith(_._2 > _._2)
}
}