scala
Scala(Scalable Language)以一种简洁、高级的语言将面向对象和函数式编程结合在一起.Scala的静态类型有助于避免复杂应用程序中的bug,它的JVM和JavaScript运行时允许您构建高性能的系统,可以轻松地访问庞大的库生态系统。
1、scala的特点:
(1)、面向对象
scala是一个纯面向对象的语言,所有的值都是对象、类和对象行为用类和特质来描述
(2)、函数式编程(项目的组成是函数)
纯函数(没有副作用)、一个参数输入,输出是确定的(中间没有涉及到其他变量、数据结构的修改,没有打印),函数要求比较高,所有函数都是值
函数等于一个值,可以作为一个普通的变量去使用
(面向过程)
(3)、静态类型
-类型在编译阶段确定–静态语言 类型在运行阶段确定–动态语言
-强类型语言:(类型转换时确定)必须强制类型转换 弱类型语言:自动类型转换
基于jvm,高性能,先编译为java的class文件,再去运行
2、为什么学scala?
1、速度快:Scala语言表达能力强,一行代码抵得上Java多行,开发速度快;Scala是静态编译的,所以和JRuby,Groovy比起来速度会快很多
2、简洁优雅:api优雅,spark源码是scala写的
3、能融合到Hadoop生态圈:Hadoop现在是大数据事实标准,Spark并不是要取代Hadoop,而是要完善Hadoop生态。JVM语言大部分可能会想到Java,但Java做出来的API太丑,或者想实现一个优雅的API太费劲。
3、环境准备
jdk1.8 、开发工具idea、安装scala
注意:路径不要有中文、空格
安装idea
安装idea 插件
解压scala
配置环境变量(SCALA_HOME、PATH)
Scala语法:
1.变量定义###
var 变量名:变量类型=初始化值 (能修改)
val 变量名:变量类型=初始化值 (不能修改)
//变量名在前,变量类型在后
scala> val str:String = "hello"
str: String = hello
scala> val t1 = 3
t1: Int = 3
scala> t1 = 5
<console>:8: error: reassignment to val
t1 = 5
^
scala> var t2 = 3
t2: Int = 3
scala> t2 = 5
t2: Int = 5
scala中:
var修饰的变量,内容和引用都可变
val修饰的变量是不可变的,注意不可变的不是内容,而是引用
举例:
scala> val arr = Array(1,2,3,4)
arr: Array[Int] = Array(1, 2, 3, 4)
scala> arr(1)
res2: Int = 2
scala> println(arr)
[I@7b22ec89
scala> arr
res4: Array[Int] = Array(1, 2, 3, 4)
scala> val arr1 = Array(5,43,65)
arr1: Array[Int] = Array(5, 43, 65)
scala> arr=arr1
<console>:9: error: reassignment to val
arr=arr1
^
scala> arr(1)=55
scala> arr
res6: Array[Int] = Array(1, 55, 3, 4)
val修饰的变量,相当于Java中final修饰的变量
可以加lazy修饰变量(只有val修饰的变量才能被lazy修饰),先不赋值,使用时再赋值
scala> lazy val t = 56
t: Int = <lazy>
scala> t
res7: Int = 56
注意:
1)可以不写类型,根据赋值去判断
2)val修饰的变量不能修改,但val修饰的变量是引用类型时可以修改(举例数组)
3)可以加lazy修饰变量(只有val修饰的变量才能被lazy修饰),先不赋值,使用时再赋值(lazy val j = 100)
2.数据类型
(数值类型 引用类型)
Scala和Java一样,有8种数值类型Byte、Char、Short、Int、Long、Float、Double和一个Boolean类型,和Java不同的是 ,Scala没有基本类型与包装类型之分,这些类型都是类,有自己的属性和方法。
Unit是值类型,他只有一个实例对象()。
Nothing是所有类型的子类,他没有一个具体的实例对象,一个常见的应用如:抛出异常、程序exit,无限循环等。
Nothing是所有类型的子类,也是Null的子类。Nothing没有对象,但是可以用来定义类型。例如,如果一个方法抛出异常,则异常的返回值类型就是Nothing(虽然不会返回) 。
Null是所有引用类型的子类,它只有一个实例对象null,主要用来和其他的JVM语言进行互操作。
详解:
数据类型 描述
Byte 8位有符号补码整数。数值区间为 -128 到 127
Short 16位有符号补码整数。数值区间为 -32768 到 32767
Int 32位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807
Float 32 位, IEEE 754 标准的单精度浮点数
Double 64 位 IEEE 754 标准的双精度浮点数
Char 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF
String 字符序列
Boolean true或false
Unit 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
Null null 或空引用
Nothing Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。
Any Any是所有其他类的超类
AnyRef AnyRef类是Scala里所有引用类(reference class)的基类
上表中列出的数据类型都是对象,也就是说scala没有java中的原生类型。在scala是可以对数字等基础类型调用方法的。
3.Scala类型转换
如:char.toInt(调用方法)
scala> val ch:Char = 'A'
ch: Char = A
scala> ch.toInt
res11: Int = 65
4.Scala操作符
Scala中没有操作符,只是以操作符的格式去进行方法调用。没有++ --,所有操作符都是方法 。
//算术运算符
+、-、* 、/、%
//关系操作符
> < >= <= != ==
//逻辑操作符
&& || !
//位操作符
| & ^ ~ << >> >>>
~:补运算符,是一元的,具有‘翻转’位的效应。
>>:带符号右移。正数右移高位补0,负数右移高位补1。
>>>:无符号右移。无论是正数还是负数,高位通通补0。
//赋值运算符
= += -= *= /= %= <<= >>= &= ^= |=
运算符优先级:不清楚时使用()进行操作
注意:
1)a + b 等价于 a.+(b)
2)Scala没有++,-- 可以用+=,-=代替
3)操作符都是方法的重载,是方法的调用
5.条件表达式
if/else表达式有值,这个值就是跟在if或者else之后的表达式的值
(条件成立/不成立)
val x = 2
if(x>0) 1 else -1
scala> val z = if(x>0) "success" else -1
z: Any = success
混合式的条件表达式,返回类型是Any
val z = if(x<0) "success" 缺失else的条件表达式,相当于:
val z = if(x<0) "success" else ()
if 嵌套 (if… else if… else…)
val n = if(x<0) 0 else if(x>=1) 1 else -1
注意:
1)每个表达式都有一个类型
2)条件表达式有值,不能在里面赋值
3)混合型表达式,结果是Any或者AnyVal
4)scala没有switch语句
6.块表达式 ### {}
在Scala中,{}中可以包含一系列表达式,块中最后一个表达式的值就是块的值
val x0 = 1
val y0 = 1
val x1 = 2
val y1 = 2
val distance = {
val dx = x1 - x0
val dy = y1 - y0
Math.sqrt(dx*dx+dy*dy)
}
println(distance)
val res1 = {
val dx = x1 - x0
val dy = y1 - y0
val res = Math.sqrt(dx*dx+dy*dy)
}
println(res1)
结果为:
1.4142135623730951
()
注意:
1)块表达式的值是最后一个表达式的值
2)赋值语句的值是Unit类型的,它的唯一实例是()
7.循环语句
在scala中有for循环和while循环,用for循环比较多
循环语法结构:
for (i <- 表达式/数组/集合)
while (条件语句){表达式}
do{表达式}while()
for (i <-1 to 10) println(i)
for (i <- 1 until 10) println(i)//until包左不包右
val s = "Hello"
for (i <- 0 to s.length-1) { // 0 until s.length
println(s(i))
}
//高级for循环
for(i <- 1 to 3;j <-1 to 3 if i == j){
//println(s"i+j=$i+$j")
println((10*i+j)+"")
println()
}
//for推导:如果for循环的循环体以yield开始,则该循环会构建一个集合或者数组,每次迭代生成其中一个值
val v = for(i <- 1 to 10 )yield i*10
println(v)
如何跳出循环?
Scala里面没有break、contine关键字,推荐使用函数式的风格解决break和contine的功能
跳出循环(要导包实现)
注意:
首先要导包
import scala.util.control.Breaks._
break:breakable()包住整个循环体
//break例子
breakable(
for (i <- 1 to 10){
if(i==5){
break()
}
println("i="+i)
})
continue:breakable()包住判断条件
//continue例子
for(j <-1 to 10){
breakable(
if(j==5){
break;
})
println("j="+j)
}
8.方法
方法定义方式:
def 方法名 (参数列表):返回值类型= {方法体}
scala> def add(x:Int,y:Int):Int=x+y
add: (x: Int, y: Int)Int
scala> add(1,2)
res15: Int = 3
带有多参数列表的方法:
scala> def addThenMultiply(x:Int,y:Int)(multiplier:Int):Int=(x+y)* multiplier
addThenMultiply: (x: Int, y: Int)(multiplier: Int)Int
scala> addThenMultiply(2,3)(4)
res17: Int = 20
无参方法:
scala> def name:String = System.getProperty("user.name")
name: String
scala> name
res19: String = brz
方法体是多行语句的表达式
scala> def area(length:Int,wide:Int):Int={
| val area = length * wide
| area}
area: (length: Int, wide: Int)Int
scala> area(4,5)
res20: Int = 20
定义默认值参数(一个方法的返回值大部分条件下返回一个值时)
带有默认值的方法:默认参数可以有多个,对位置也不做要求,传值默认是按顺序传的,可以带名称传值
def method1(a:Int=1,b:Int,c:Int=3) = println("a="+a+"b="+b+"c="+c)
//调用
method1(b=2) //不能method1(2)
//或者
method1(1,2) //method1(a=1,b=2)
//或者
method1(1,2,3) //method1(c=1,b=2,a=3)
可变参数或不定长参数
scala> def varele(a:Int*){
| for(i<-a){
| println(i)}
| }
varele: (a: Int*)Unit
scala> varele(1,2,3,4)
1
2
3
4
scala> var arr = Array(1,2,3,4)
arr: Array[Int] = Array(1, 2, 3, 4)
scala> varele(arr:_*)
1
2
3
4
注意1:可变参数一定是参数列表的最后一个参数
注意2:函数内部,重复参数的类型是声明参数类型的数组,但是如果你给一个可变参数的方法传一个数组,是会报编译错误:type mismatch,可以使用数组名:_*的方式传参
注意:
1)方法的返回值类型可以不写,编译器可以自动推断出来,但是对于递归函数,必须指定返回类型
2)方法的返回值默认是方法体中最后一行表达式的值,当然也可以用return来执行返回值,但不推荐这么做。
3)若使用 return 来制定函数的返回值,scala的类型推断将会失效,要显式指定返回值类型。
4)方法也可以没有返回值(返回值是Unit)
9.函数
给方法传递一个函数类型的参数:
def foo(f: Int => String) = …
def bar(f:(Boolean,Double)=>List[String])=…
函数可以看做是带有参数的表达式。
函数的定义方式:
-1-
val f1 = (a: Int, b: Int) => a + b //推荐使用这种定义方式
val f2 = ((a: Int, b: Int) => a + b)
val f3 = (_: Int) + (_: Int)
val f4: (Int, Int) => Int = (_ + _)
-2-
val f1:((Int,Int)=>Int)={(x,y)=>x+y}
val f2:(Int,Int)=>Int =(x,y)=>x+y
-3-
val f1 = new Function2[Int, Int, Int] {
def apply(x: Int, y: Int): Int = if (x < y) y else x
}
匿名函数:
(x:Int)=>x+1
多参数函数:
val ff = (x:Int,y:Int)=>x+y
无参函数:
scala> val getTheAnswer = () => 42
getTheAnswer: () => Int = <function0>
scala> println(getTheAnswer())
42
scala> println(getTheAnser)
<function0>
方法和函数的区别:
方法和函数的定义语法不同
方法一般定义在某个类、特质、或者object中
方法可以共享使用所在类内的属性
在函数式编程语言中,函数是“头等公民”,可以调用它,也可以传递它,存放在变量中,或者作为参数传递给另一个函数
举例:首先定义一个方法,再定义一个函数,然后将函数传递到方法里面
scala> def m(f:(Int,Int)=>Int)=f(2,6)
m: (f: (Int, Int) => Int)Int
scala> val f2 = (x:Int,y:Int)=>x-y
f2: (Int, Int) => Int = <function2>
scala> m(f2)
res37: Int = -4
将方法 转化为 函数:
把方法作为参数传给另一个方法或者函数的时候,方法被转化成函数,使用下划线(“ ”,“,_”)
scala> def ff(x:Int,y:Int)=x+y
ff: (x: Int, y: Int)Int
scala> ff _
res38: (Int, Int) => Int = <function2>
scala> ff(_,_)
res39: (Int, Int) => Int = <function2>
###(10)集合 ###
集合是一种用来存储各种对象和数据的容器,Scala 集合分为可变的和不可变的集合。
可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素;而不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
可变集合 不可变集合(推荐使用)
对值得删除修改添加扩容
可以(在之前的上直接改) 不可以(模拟修改得到新的集合)
推荐使用不可变的集合,效率高,占空间少,如果需要,可以转换为可变的集合
https://docs.scala-lang.org/overviews/collections/overview.html
了解集合的区别、创建、方法
11.数组(Array)
数组元素内容要求类型一致。
定长数组,数组不可扩容
变长数组,数组可扩容
定长数组
1)创建一个定长数组的方式:
(1)使用new关键字创建一个定长数组:
val arr2 = new ArrayInt
(2)直接使用Array创建并初始化一个数组:
val arr1 = ArrayInt
注意:
val arr1 = ArrayInt//初始化一个长度为1,值为10的定长数组
val arr2 = new ArrayInt 初始化一个长度为10的定长数组,其所有元素均为0scalaval arr1 = ArrayInt
arr1: Array[Int] = Array(10)scalaval arr2 =new ArrayInt
arr2: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
//初始化一个长度为9的定长数组,其所有元素均为0
val arr1 = new Array[Int](9)
println(arr1)//直接打印定长数组,内容为数组的hashcode值
//将数组转换成数组缓冲,就可以看到原数组中的内容了
println(arr1.toBuffer)//toBuffer会将数组转换长数组缓冲
//初始化一个长度为1,值为9的定长数组
val arr2 = Array[Int](9)
println(arr2.toBuffer)
//使用()来访问元素
println(arr2(0))//下标从0开始
//遍历数组
for(i<-0 to arr1.length-1){
println(arr1(i))
}
//访问并修改元素值
arr1(5)
arr1(6)=10
for(i<-0 until arr1.length){
print(s"$i:${(arr1(i))}")
println()
}
2)变长数组
定义变长数组的方式(2种):
import scala.collection.mutable.ArrayBuffer
var arr3 = ArrayBufferInt//定义一个空的可变长Int型数组
var arr4 = ArrayBufferInt //初始值为10
new时会创建一个长度为0的数组
var arr5 = new ArrayBuffer[Int](10)
等价于
var arr5 = new ArrayBuffer[Int]()
3)数组的增删改
-1-添加元素
//使用+=在尾端添加一个或者多个元素
arr5 += 1
arr5 += (2,3,4)
//使用++=在尾端添加任何集合
arr5 ++= Array(5,6,7)
//使用append追加一个或者多个元素
arr5.append(8)
arr5.append(9,10)
//在下标2之前插入元素
arr5.insert(2,20)
arr5.insert(2,30,30)
-2-移除:
arr5 -= 20
arr5 --= Array(20,9)
arr5.trimEnd(2) 从尾部移除2个元素
arr5.trimStart(2) 从头部部移除2个元素
//从下标2出移除一个或者多个元素
arr5.remove(2)
arr5.remove(2,2)
-3-修改
arr5(1)=10
-4-数组遍历
(1).增强for循环
for(item <- arr5) println(item)
(2).好用的until会生成脚标
for(i <- 0 until arr5.length) println(arr5(i))
4)定长数组与变长数组的转换
定长--> 变长
val arr6 = Array(1,2,3)
arr6.toBuffer
arr6.toArray
5)数组转换
yield关键字将原始的数组进行转换会产生一个新的数组,原始的数组不变
//使用for推导生成一个新的数组
val a = Array(1,2,3,4,5,6,7,8,9)
val res1 = for(i<-a)yield i*2
for(m<-res1){
println(m)
}
//对原数组元素过滤后生成一个新的数组
//将偶数取出乘以10后再生成一个新的数组
val res2 = for(i<-a if i%2 == 0) yield 10*i
for (n<-res2){
println(n)
}
//使用filter和map转换出新的数组
val res3 = a.filter(_%2==0).map(10 * _)
for (q<-res2){
println(q)
}
6)数组常用方法
arr6.sum//求和
arr6.max//最大值
arr6.min//最小值
arr6.sorted//排序
arr6.sortWith(_>_)//指定排序方式
12.映射(Map)###
在Scala中,把哈希表这种数据结构叫做映射
1)构建映射
在Scala中,有两种Map,一个是immutable包下的Map,该Map中的内容不可变;另一个是mutable包下的Map,该Map中的内容可变。
(1)构建一个不可变的map
val scores = Map("zhangsan"->90,"lisi"->80,"wangwu"->70)
val scores = Map(("zhangsan",90),("lisi",80),("wangwu",70))
(2)构建一个可变的map
val scores = scala.collection.mutable.Map(("zhangsan",90),("lisi",80),("wangwu",70))
2)访问映射中的值
根据键获取map中对应的值,可以有以下三种方法,尤其推荐使用getOrElse方法。
val score1 = scores("lisi")
val score2 = if(scores.contains("lisi")) scores("lisi") else 0
val score3 = scores.getOrElse("lisi",0) //0为默认值,如果不存在则返回默认值
3)修改键对应的值
scores("tom") = 99
scores("tom11") = 99 不存在时会添加一个值
scores.update("tom",66)
4)添加、移除键值对
scores +=(“mary”->55)
scores - “tom”
scores ++= Map("tom"->55,"mary1"->44)
scores --= List("mary","tom")
-
遍历map
val keys = scores.keySet set集合
val key = scores.keys 返回一个迭代器
val value = scores.values 返回值的迭代器for((k,v)<-scores) println(k+" “+v) 返回键值对
for (item <- scores) print(item+” ") 返回键值对
6)HashMap(可变map)
val hashmap = new scala.collection.mutable.HashMap[String,Int]()
//向map中添加数据
map1("spark") = 1
map1 += (("hadoop", 2))
map1.put("storm", 3)
//从map中移除元素
map1 -= "spark"
map1.remove("hadoop")
7)TreeMap、SortedMap(有序的map)
返回按特定顺序排列的元素集合。
var treemap = scala.collection.immutable.TreeMap(3->"hadoop",1->"scala",2->"hadoop")
var SortedMap = scala.collection.immutable.SortedMap(3->"hadoop",1->"scala",2->"hadoop")
13.元组(Tuple)
映射是K/V对偶的集合,对偶是元组的最简单形式,元组可以装着多个不同类型的值,是不同类型的值的聚集
创建元组:使用小括号将多个元素括起来,元素之间用逗号分隔,元素的类型和个数任意
访问组元:使用_1, _2, _3等访问组元
(1)定义方式(2种)
定义1:val tuple = (“scala”,“spark”,1,2)
定义2:val tuple = new Tuple4(“scala”,“spark”,1,2) 元组元素个数要与Tuple4相同
取元组中的元素值
val t_1 = tuple._1
也可以通过a,b,c去访问组元
val tuple,(a,b,c)=(“scala”,“spark”,1)
目前 Scala 支持的元组最大长度为 22。对于更大长度你可以使用集合,或者扩展元组
1)元组访问:
注意元组元素的访问有下划线,并且访问下标从1开始,而不是0
val value1 = tuple._3
2)元组遍历
方式1:
for (elem <- tuple.productIterator) {
println(elem)
}
方式2:
tuple.productIterator.foreach(i => println(i))
tuple.productIterator.foreach(print(_))
3)拉链操作
使用zip方法把元组的多个值绑在一起,以便后续处理
A zip B
注意:如果两个数组的元素个数不一致,拉链操作后生成的数组的长度为较小的那个数组的元素个数
14.列表(List)
列表是同质的,列表中的元素类型是一致的,列表是有序的。
不可变的序列
import scala.collection.immutable._
val fruit = List("apples", "oranges", "pears")
所有的列表可以看做是由两个基础构造快Nil和中缀操作符::构成,::表示从列表前段扩展。
在Scala中列表要么为空(Nil表示空列表),要么是一个head元素加上一个tail列表。
:: 操作符是将给定的头和尾创建一个新的列表
注意:
:: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))
1)列表的访问
val nums = 1 :: 2 :: 3 :: 4 :: list0 :: Nil
nums(0)
2)列表的追加
将0插入到lst1的前面生成一个新的List ::和+:右结合
val lst1 = List(1,2,3)
//将元素0添加到lst1的前面产生一个新的集合
val lst2 = 0 :: lst1
val lst3 = lst1.::(0)
val lst4 = 0 +: lst1
val lst5 = lst1.+:(0)
//将一个元素添加到lst1的后面产生一个新的集合,:+左结合
val lst6 = lst1 :+ 3
val lst0 = List(4,5,6)
//将2个list合并成一个新的List
val lst7 = lst1 ++ lst0
//将lst1插入到lst0前面生成一个新的集合
val lst8 = lst1 ++: lst0
//将lst0插入到lst1前面生成一个新的集合
val lst9 = lst1.:::(lst0)
3)对列表的操作
对列表的所有操作可以表达为一下三种:
head 返回列表的第一个元素。
tail 返回除第一个元素之外所有元素组成的列表。
isEmpty 返回列表是否为空。
scala> lst1.head
res40: Int = 1
scala> lst1.tail
res42: List[Int] = List(2, 3)
scala> lst1.isEmpty
res43: Boolean = false
注意:其中tail head作用在空列表上,会报异常
4) 列表的常用方法
//连接操作
scala> List(1, 2) ::: List(3, 4, 5)
res8: List[Int] = List(1, 2, 3, 4, 5)
//求列表长度
scala> List(1,2,3).length
//反转列表
scala> abcde.reverse
//提取列表的前n个元素
scala> abcde take 2
//丢弃列表的前n个元素
scala> abcde drop 2
//拉链操作
scala> abcde zip List(1,2,3,4,5)
5)可变列表
import scala.collection.mutable.ListBuffer
val list = ListBuffer(1,2,3,4,5)
list += 6
list ++= List(7,8,9)
list -= 1
14.集合:set
不可变的set
val set = Set(1,2,3)
import scala.collection.immutable.HashSet
val set = new HashSet(2,3,4,5,6) 错误
var set = new HashSet[Int]() 正确
//将元素和set1合并生成一个新的set,原有set不变
set+=1
set = set+4 不可以重复加入,(去重),无序
可变的set
import scala.collection.mutable.HashSet
var set1 = new HashSet[Int]()
set1 = set1+4
set1 += 5
基本操作:Scala集合有三个基本操作:head/tail/isEmpty
最值:查找集合中最大与最小元素 你可以使用 Set.min 方法来查找集合中的最小元素,使用 Set.max 方法查找集合中的最大元素
两个集合间的操作:可以使用 ++ 运算符或 Set.++() 方法来连接两个集合。如果元素有重复的就会移除重复的元素
交集:可以使用 Set.& 方法或 Set.intersect 方法来查看两个集合的交集元素
官网API:https://docs.scala-lang.org/
15.集合高级运用
1)集合的重要函数:sum/max/min/count
val seq = Seq(1,2,3,4,5)
seq.max
seq.min
seq.count(_%2==0) //根据条件计数
2)过滤
seq.filter(_%2==0) 返回符合Boolean条件的结果
3)map:(映射)列表元素
map函数的逻辑是遍历集合中的元素并对每个元素调用函数
scala> val seq = Seq(1,2,3,4,5)
seq: Seq[Int] = List(1, 2, 3, 4, 5)
scala> seq.map(n=>n*2)
res56: Seq[Int] = List(2, 4, 6, 8, 10)
scala> seq.map(_*2)
res57: Seq[Int] = List(2, 4, 6, 8, 10)
4)flatten、flatMap
当有一个集合的集合,然后你想对这些集合的所有元素进行操作时,就会用到 flatten。
flatten:脱壳,压平、取集合里面的元素
flatMap:先map操作,再进行flatten操作
scala> val s1 = Seq(1,2,3)
s1: Seq[Int] = List(1, 2, 3)
scala> val s2 = Seq(4,5,6)
s2: Seq[Int] = List(4, 5, 6)
scala> val s = Seq(s1,s2)
s: Seq[Seq[Int]] = List(List(1, 2, 3), List(4, 5, 6))
scala> s.flatten
res59: Seq[Int] = List(1, 2, 3, 4, 5, 6)
flatMap()
val list = List(1,2,3,4,5)
list.flatMap(n=>List(n*10,n))
scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)
//map后压平
scala> list.flatMap(n=>List(n*10,n)) //List(List(10,1),List(20,2),List(30,3),List(40, 4),List(50, 5))
res12: List[Int] = List(10, 1, 20, 2, 30, 3, 40, 4, 50, 5)
5)集合之间的操作(差集、交集和并集)
num1.diff(num2)
num1.intersect(num2)
num1.union(num2)
如果我们不需要重复怎么办?这时可以使用 distinct 函数
num1.union(num2).distinct
6) 对整个集合进行条件检查
确保集合中所有元素都要符合某些要求,如果有哪怕一个元素不符合条件,就需要进行一些处理:
scala> val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)
numbers: Seq[Int] = List(3, 7, 2, 9, 6, 5, 1, 4, 2)
scala> numbers.forall(n => n < 10)
res64: Boolean = true
scala> numbers.forall(n => n > 5)
res65: Boolean = false
而 forall 函数就是为处理这类需求而创建的。
foreach /take
scala> val list = List(1,9,5,6,7).foreach(println)
1
9
5
6
7
list: Unit = ()
7)对集合进行分组
val seq1 = Seq(1,2,3,4,5,6,7)
val res = seq1.partition(_%2==0) 分组
8)Fold
一个流行的操作是 fold。在 Scala 的上下文中,通常可以考虑 foldLeft 和 foldRight。他们是从不同的方面做同样的工作:
fold foldLeft foldRight
scala> val seq2 = Seq(1, 2, 3, 4, 5)
seq2: Seq[Int] = List(1, 2, 3, 4, 5)
scala> seq2.foldLeft(0)(_+_) //从左边做运算,0当做初始值
res71: Int = 15
scala> seq2.foldLeft(10)(_-_)
res75: Int = -5
scala> seq2.foldRight(10)(_-_)
res72: Int = -7
第一对括号中,我们放一个起始值。 在第二对括号中,我们定义需要对数字序列的每个元素执行的操作
seq2.foldLeft(0)((res, n)=> res + n)
val words = Seq(“apple”, “dog”, “table”)
words.foldLeft(0)((resultLength, word) => resultLength + word.length)
foldLeft, reduceRight, foldRight
方法foldLeft与reduceLeft工作方法很想,但是它让你指定一个值作为第一个元素。下面这个例子真是了求和算
法,第一个是reduceLeft方法,后面是foldLeft方法,我们来看看它们的区别:
scala> seq2.reduceLeft(_-_)
res76: Int = -13
scala> seq2.reduceRight(_-_)
res77: Int = 3
seq2.reduceLeft(-)
seq2.reduceRight(-)
(1 to 100).foreach(println)
(1 to 100).par.foreach(println) //par并行执行