object Demo09Func2 {
/**
* 面向函数(函数式编程、高阶函数)
* 1、函数作为参数
* 2、函数作为返回值
*
* 面向对象编程:将对象传来传去 对象可以作为函数的参数或返回值传来传去 注意有类型的约束
* 面向函数编程:将函数传来传去 函数可以作为函数的参数或返回值传来传去 注意有类型的约束
*
* 如何描述函数的类型
* 跟def无关
* 跟方法名无关
* 跟方法体无关
* 跟参数的名称无关
*
* 函数的类型跟该函数“参数的类型、参数的个数、参数的顺序、返回值类型”有关
* (参数,参数) => 返回值类型
*/
//这是一个“参数只有一个类型String 返回值类型为Int”这样的函数
//String=>Int
def func1(str:String): Int ={
str.toInt+100
}
//这是一个“参数只有一个类型String 返回值类型为Int”这样的函数
//String=>Int
def func2(str:String): Int ={
str.toInt+200
}
//这是一个“参数只有一个类型Int 返回值类型为String”这样的函数
// Int=>String
def func3(int:Int): String ={
int+300+""
}
//可以接收一个函数并进行调用
//接收一个"String=>Int" 这样类型的
def funcX(func:String=>Int) ={
println(func("500"))
}
/**
* 匿名函数(类似lambda表达式):没有名字的函数
* (参数名:参数类型,参数名:参数类型,参数名:参数类型)=>{方法体}
*/
(str:String)=>{str.toInt+200}
//匿名函数也可以拥有名称
val func4: String => Int = (str:String)=>{str.toInt+400}
val func5: String => Int = (str)=>{str.toInt+500}
def main(args: Array[String]): Unit = {
funcX(func1)
funcX(_.toInt+100)//用匿名函数替代
funcX(func2)
funcX(_.toInt+200)//用匿名函数代替func2的逻辑
//funcX(func3) //func3不符合funcX的定义
funcX(func4)
/**
* 匿名函数的简化
* 1、如果代码只有一行 花括号可以省略
* 2、如果匿名函数值为 参数 传入另外一个函数 则匿名函数的参数类型可以省略
* 3、如果匿名函数只有一个参数则括号可以省略
* 4、如果匿名函数中的参数在逻辑中只使用了一次 则可以用下划线代替 然后 => 左边的部分可以省略
*/
funcX((str:String)=>{str.toInt+300})//太繁琐 很多东西可以省略
funcX((str:String)=>str.toInt+300)
funcX((str)=>str.toInt+300)
funcX(str=>str.toInt+300)
funcX(_.toInt+300)//可读性比较低
}
}
600
600
700
700
900
800
800
800
800
800
object Demo10Func3 {
//以函数作为参数 应用
def main(args: Array[String]): Unit = {
val arr: Array[Int] = Array[Int](1, 2, 3, 4, 5, 6, 7)
//遍历数组
/**
* Java的思想
* for(int i=0;i<arr.length;i++){
* System.out.println(arr[i]);
* }
*/
//Scala的方式 类似Java中增强for(for—each)
for (elem <- arr) {
println(elem)
}
println("*"*20)
/**
* foreach方法可以接收一个函数f
* 函数f的类型: Int=>U
* Int:arr中的每一个元素的类型是 Int
* U:相当于Unit 表示没有返回值
*
* println函数:Any => Unit
*/
arr.foreach(println)//foreach 会将arr中的每一个元素作为参数 传给println方法
println("*"*20)
//将arr中的每个元素扩大一倍 并构建一个新的arr
//用Java的思想做
var count:Int=0
val arr2: Array[Int] = new Array[Int](arr.length)
while(count<arr.length){
arr2(count)=arr(count)*2
count+=1
}
//mkString 可以指定一个分隔符 将arr2中的每个元素与分隔符拼接 返回一个 字符串
//类似Python中的join方法
println(arr2.mkString(","))
println("*"*20)
//以函数式编程的思想来实现
val arr3: Array[Int] = new Array[Int](arr.length)
def extend1(int: Int): Unit ={
println(int*2)
}
var count2:Int=0
arr.foreach((elem:Int)=>{
arr3(count2)=elem*2
count2+=1
})
println(arr3.mkString("|"))
println("*"*20)
/**
* map 方法也需要接收一个函数f:
* 函数f:Int=>B
* Int:arr中的每一个元素的类型是 Int
* B:表示返回值类型由自己指定
*
* map 和 foreach最大的区别在于 有无返回值
*/
val arr4: Array[Int] = arr.map((elem: Int) => {
elem*2
})
println(arr4.mkString(","))
println("*"*20)
//简化
println(arr.map((elem: Int) => {elem*2}).mkString("/"))
println(arr.map((elem) => {elem*2}).mkString("/"))
println(arr.map(elem => {elem*2}).mkString("/"))
println(arr.map(elem => elem*2).mkString("/"))
println(arr.map(_*2).mkString("/"))
println("*"*20)
println(arr.map(_*2).mkString("|"))
println(arr.map(_*3).mkString("|"))
println(arr.map(_*4).mkString("|"))
println(arr.map(_*1.5).mkString("|"))
println(arr.map(_*0.5).mkString("|"))
println("*"*20)
}
}
1
2
3
4
5
6
7
********************
1
2
3
4
5
6
7
********************
2,4,6,8,10,12,14
********************
2|4|6|8|10|12|14
********************
2,4,6,8,10,12,14
********************
2/4/6/8/10/12/14
2/4/6/8/10/12/14
2/4/6/8/10/12/14
2/4/6/8/10/12/14
2/4/6/8/10/12/14
********************
2|4|6|8|10|12|14
3|6|9|12|15|18|21
4|8|12|16|20|24|28
1.5|3.0|4.5|6.0|7.5|9.0|10.5
0.5|1.0|1.5|2.0|2.5|3.0|3.5
********************
object Demo11Func4 {
//以函数作为返回值
//将函数作为返回值时 返回值的类型得手动指定
def func1(str1:String):String=>Int={
println("func1被调用")
//String => Int
def func1_1(str2:String): Int ={
println("func1_1被调用")
str1.toInt+str2.toInt
}
func1_1
}
//简化定义
//将函数作为返回值时 返回值的类型得手动指定
//函数的柯里化:将有N个参数的函数变成N个只有一个参数的函数
def func2(str1:String)(str2:String):Int={
str1.toInt+str2.toInt
}
//不使用函数作为返回值
def func3(str1:String,int:Int): Int={
str1.toInt+int
}
//偏应用函数:将有N个参数函数 变成N-X个参数的函数 X表示已经固定的参数
//计算a的b次方,如果不给定b,则计算a的三次方
//第一种方式:使用默认参数
def aPowerB(a:Int,b:Int=3): Unit ={
println(Math.pow(a,b))
}
//第二种方式:使用函数式编程的思想
def aPowerB2(a:Int)(b:Int): Unit ={
println(Math.pow(b,a))
}
def main(args: Array[String]): Unit = {
val func1_1: String => Int = func1("100")
val i: Int = func1_1("200")
println(i)
//简化调用
println(func1("100")("200"))
println(func2("300")("400"))
println(func3("500",600))
aPowerB(2,2)
aPowerB(2,3)
aPowerB(2,4)
aPowerB(2)
//偏应用函数:将有N个参数函数 变成N-X个参数的函数 X表示已经固定的参数
val aPower3: Int => Unit = aPowerB2(3)
aPower3(2)
aPower3(3)
aPower3(4)
aPowerB2(4)(2)
}
}
func1被调用
func1_1被调用
300
func1被调用
func1_1被调用
300
700
1100
4.0
8.0
16.0
8.0
8.0
27.0
64.0
16.0
object Demo12List {
def main(args:Array[String]): Unit ={
/**
* List列表
* 特点:元素可以重复、有序的、不可变的
*/
//定义一个List
val list1: List[Int] = List[Int](1, 2, 1, 2, 3, 5, 7, 3, 4, 6, 4, 9, 8)
println(list1)
//通过下标(index,索引)取元素
println(list1(4))
//list1(4)=10 //List不能修改
//List中常用的方法
println(list1.max)//最大值
println(list1.min)//最小值
println(list1.sum)//求和
println(list1.head)//取第一个元素
println(list1.tail)//取除第一个元素以外的元素
println(list1.length)//长度 同size
println(list1.take(3))//取前N个元素
println(list1.distinct)//返回去重后结果
println(list1.isEmpty)//判断是否为空
println(list1.size)//大小 同length
println(list1.reverse)//倒转List
//List常见的操作
/**
* map 和 foreach
* 区别:有无返回值
* 都需要接收一个函数f
* 都会将List中的每个元素传给函数f
*/
//有返回值
val newList1: List[Int] = list1.map(elem => elem * elem)
println(newList1.mkString(","))
//遍历
list1.foreach(println)
//过滤
/**
* filter方法:
* 接收一个函数类型的参数p
* p:Int=>Boolean
* 函数p的参数类型为Int:因为list1中的每个元素的类型为Int
* 函数p的返回值类型为Boolean
* filter会根据函数p最后的返回值进行过滤
* true: 保留数据
* false: 将数据过滤
*/
//将奇数过滤出来
def filterList1(elem:Int): Boolean ={
var flag:Boolean=false
if(elem%2==1){
flag=true
}
flag
}
//使用一般的函数
val filterList: List[Int] = list1.filter(filterList1)
println(filterList.mkString(","))
//使用匿名函数
val filterList2:List[Int]=list1.filter((elem:Int)=> {
var flag: Boolean = false
if (elem % 2 == 1) {
flag=true
}
flag
})
println(filterList2.mkString(","))
//简写
println(list1.filter(elem => elem % 2==1).mkString(","))
println(list1.filter(_%2==1).mkString(",")) //偶数
println(list1.filter(_%2==0).mkString(",")) //奇数
//groupBy 需要指定一个分组“字段”
val zs: Stu = Stu("001", "zs", 20, "文科一班")
val ls: Stu = Stu("002", "ls", 21, "文科二班")
val ww: Stu = Stu("003", "ww", 22, "文科三班")
val zl: Stu = Stu("004", "zl", 21, "理科二班")
val lj: Stu = Stu("005", "lj", 20, "理科一班")
val stuList: List[Stu] = List[Stu](zs, ls, ww, zl, lj)
//按班级分组
/**
* 得到一个Map
* Map的Key就是指定的分组“字段”表示每一组
* Map的value就是经过分组过后属于同一组的元素一同构成的List
*/
// stuList.groupBy((stu:Stu)=>{stu.clazz})
val groupStu: Map[String, List[Stu]] = stuList.groupBy(_.clazz)
println(groupStu)
}
case class Stu(id:String,name:String,age:Int,clazz:String)
}
List(1, 2, 1, 2, 3, 5, 7, 3, 4, 6, 4, 9, 8)
3
9
1
55
1
List(2, 1, 2, 3, 5, 7, 3, 4, 6, 4, 9, 8)
13
List(1, 2, 1)
List(1, 2, 3, 5, 7, 4, 6, 9, 8)
false
13
List(8, 9, 4, 6, 4, 3, 7, 5, 3, 2, 1, 2, 1)
1,4,1,4,9,25,49,9,16,36,16,81,64
1
2
1
2
3
5
7
3
4
6
4
9
8
1,1,3,5,7,3,9
1,1,3,5,7,3,9
1,1,3,5,7,3,9
1,1,3,5,7,3,9
2,2,4,6,4,8
Map(理科一班 -> List(Stu(005,lj,20,理科一班)), 理科二班 -> List(Stu(004,zl,21,理科二班)), 文科一班 -> List(Stu(001,zs,20,文科一班)), 文科二班 -> List(Stu(002,ls,21,文科二班)), 文科三班 -> List(Stu(003,ww,22,文科三班)))