Scala编程基础——集合&高阶函数
集合
Scala中集合分为可变集合和不可变集合
可变集合:可以修改、添加、移除一个集合的元素。
不可变集合:安全的并发访问。
不可变集合,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
// 不可变集合
scala.collection.immutable (Scala默认采用不可变集合)
// 可变集合
scala.collection.mutable
数组
定长数组Array
创建数组
//创建数组,长度为10,int数据类型
var arr1 = new Array[Int](10)
//数组创建存在默认值,与泛型有关
println(arr1)//不可变数组无法直接打印数组中的值,打印数组名得到地址
另一种创建数组方式,不使用new关键字【触发apply】
var arr2 = Array(1,2,3)
//指定数据类型的泛型,即指定数组中存储的数据类型
val arr3 = Array[String](xs = "HDFS","Zookeeper")
变长数组arrayBuffer
/*
定义可变数组
Scala中默认使用是不可变的集合操作,如果需要使用可变集合
需要导入可变集合包 scala.collection.mutable.ArrayBuffer
*/
//定义一个可变Int类型数组
val nums = ArrayBuffer[Int]();
//向集合中添加数据【集合的末尾】
// nums(0) = 1;
// println(nums)
//上面方式对于变量数组赋值是不允许的
nums += 1
println(nums)
//在末尾添加多个元素
nums += (2,3,4,5)
//使用++=在尾端添加任何集合
nums ++= Array(6,7,8)
println(nums)
//这些运算操作符也有相应的 -=,--=可以作为数组的删减
//使用append方法向数组中追加一个或多个数据
nums.append(1);
nums.append(2,3)
println(nums)
//有数据的前提下,在指定下标位置之前插入数据(一个或多个数据)
nums.insert(2,20);
nums.insert(2,30,30)
println(nums)
//移除(删除)最后2个元素
nums.trimEnd(2)
println(nums)
//移除最开始的一个或多个元素
nums.trimStart(1)
println(nums)
//删除数组中数据-->删除指定数据(下标位置)
nums.remove(2)
println(nums)
//删除数组中数据-->删除指定数组(下标位置)开始删除多少个
nums.remove(2,2)
println(nums)
/*
可以使用Scala中增强for循环进行数组的遍历
for(变量 <- 数组名){
操作变量就相当于获取到数中对应数据
}
*/
for(ele <- nums){
println(ele)
}
//使用下标的方式遍历(要求数中要有数据)
for(i <- 0 until nums.length){
println(nums(i))
}
定长数组与变长数组的转换
定长数组名.toBuffer //转为变长
变长数组名.toArray //转为定长
//将定长数组转换为变长数组
println(arr1.toBuffer)
//将变长数组转换为定长数组
println(arr2.toArray)
遍历数组
Scala与Java拥有同一概念–>下标,通过下标值,可以获取数组中的元素
val ints:Array[Int] = new Array[Int](10)
//for循环遍历数组
for(i <- ints){
println(i)
}
for(i<- 0 until ints.length){
println(ints(i))
}
数组元素处理
val ints:Array[Int] = new Array[Int](10)
//修改数组中的值
ints(0) = 10000;
println(ints.toBuffer)
//扩容
ints(10)=111
println(ints.toBuffer)
//使用可变集合必须导入包
import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer[Int]()
//可以使用下标 推荐使用 += 运算符
buffer += 1
println(buffer)
//添加多个数据
buffer += (2,3,4,5,6)
println(buffer)
//++= 在集合的尾部添加任何集合存储的数据到当前集合
buffer ++= Array(7,8,9)
println(buffer)
//使用append进行数据添加
buffer.append(1)
//insert在指定下标位置进行数据插入
buffer.insert(2,101,102)//下标为2
println(buffer)
//删除数组中的数据【删除最后几个数据-->几个根据参数决定】
buffer.trimEnd(2)//删除最后两个元素
buffer.trimStart(2)//删除最开始两个元素
buffer.remove(2)//删除下标为2的元素
buffer.remove(2,3)//从第一个参数位置开始删除后续多个数据
//遍历
for(i<- buffer){
println(i)
}
数组的常用方法
数组中提供了比较常见处理数据的操作
val arr =Array(1,2,3,4,5,6,7,8,9)
println(arr1.sum)//求数组中数据之和
println(arr1.max)//求数组中最大的元素
println(arr1.min)//求数组中最小的元素
println(arr1.sorted.toBuffer)//数组排序(默认升序),返回一个新的数组
/*
可以根据自定义规则规则进行排序操作sortWith
_>_ 升序 _<_ 降序
*/
println(arr1.sortWith(_<_).toBuffer);
val arr =Array(1,2,3,4,5,6,7,8,9)
for(i <- arr){
print(i*2)
}
for(i <- arr){
if(i%2 == 0){
println(i*2)
}
}
val res = for(ele <- arr)yield ele*2
val res2=for(ele <- arr if(ele%2==0))yield ele*2
//利用封装好的方法进行处理
/*
记忆:map方法:遍历 集合中的每一个元素,并在参数的位置 提供一个可以处理集合元素函数操作
*/
val ints:Array[Int] = arr.map(x => x * 2)
//filter 遍历集合中的每一个元素,并在参数位置提供一个判断的逻辑 对数据进行操作
val ints1:Array[Int] = arr.filter(x => x % 2 == 0).map(y => y * 2)
//至简原则
//_ 属于简化写法 等价于变相定义了 x 这个变量 _ 获取集合中每一个元素
arr.map(_*2)
arr.filter(_%2==0).map(_*2)
val arr1=Array(1,23,4,5,4,7)
arr1.sortWith((x,y)=>x>y)
元组(Tuple)
表示固定元素的组合,元素可以装着多个不同类型的值,是不同类型的值的聚集。
特点:
- 最多支持22个元素组合,分别对应类型Tuple1~Tuple22
- 元组可以容纳不同类型的元素
- 元组不可变
特别地:二元组(v1,v2)可以表示Map中的一个元素(key,value),Map是K/V对偶的集合,对偶是元组的最简单形式。
创建访问元组
创建元组:使用小括号()
将多个元素括起来,元素之间用逗号分隔,元素的类型和个数不超过22。
访问组元:使用_1
, _2
,_3
等形式访问组元,注意下标从1开始。
第二种方式定义的元组也可以通过a
,b
,c
去访问组元。
//定义元组
/*
t 就是元组名称 代表整个元组
()数据
*/
val t = ("hadoop","yarn","spark","zookeeper")
println(t)
//获取元组中某一个值,元组中数据是存在的,整个位置从1开始 递增+1
//表示形式_数字 获取对应位置
println(t._1)
//abc对应元组数据,访问变量名获取数据
val t2,(a,b,c)=("hadoop",1,123)
println(c)
//标准元组创建方式
val t3 =new Tuple4("hadoop","yarn","spark","zookeeper")
//元组中提供的方法productElement这个方法的参数是元组数据位置【参考下标形态】
//开始值从0开始
println(t3.productElement(0))
//元组的遍历 元组本身不是集合的成员 不能直接在for中使用
//需要将元组转换为元组迭代器对象才可以进行操作
for(i<- t.productIterator){
println(i)//获取元组中每一个元素
}
//必须记住的地方 foreach 遍历集合中每一个元素用于打印操作
t.productIterator.foreach(x=> println(x))
t.productIterator.foreach(println(_))
元组访问
//Scala中已经定义好的元祖对象,根据数字决定元祖中存储数据个数
val tuple3 = new Tuple3(1,3.14,"true");
/*
注意访问元祖中数据可以使用【_数字】 的形式访问
数字是从1开始 根据元祖中存数据个数递增+1
*/
println(tuple3._3)
/*
元祖中也提供一个方法productElement
这个方法参数值是 元祖中存数据的下标,第一个数据下标是从0开始的
*/
println(tuple3.productElement(0))
元组遍历
因为元组本身不是集合成员,所以元组不能作为for生成器的表达式。但元组实现了productIterator()
方法,该方法可以生成元组的迭代器Iterator
(继承自TraversableOnce
),迭代器提供了遍历集合的方法。这也是通常我们将Tuple视为集合的原因。
方式一:
//第一种遍历元祖的方式
for(ele <- tuple3.productIterator){
println(ele)
}
方式二:
// foreach 遍历集合中每一个元素用于打印操作
/*
第二种遍历元祖的方式利用productIterator中foreach方法进行数据打印
foreach属于高阶函数
*/
tuple3.productIterator.foreach(i => println(i))
//简化版本 使用 【_】 替代参数的定义
tuple3.productIterator.foreach(println(_))
}
zip拉链操作
//拉链操作(将两个集合中的内容合并到一个集合)
//ps:两个集合中元素个数相等时
val num1 = Seq(1,2,3,4)
val num2 = Seq(5,6,7,8)
val num3 = num1 zip num2//将形成新集合,存储数据形式类似于Map集合中kv键值对
//集合中元素个数不一致时,以最短集合长度作为合并依据,多余的数据会被删除
val num4 = Seq(1,2,3)
val num5 = Seq(1,2,3,4)
val num6 = num4 zip num5
println(num6)
//zipAll函数与zip函数是相似的,也是进行数据的拉链操作。如果有较少数据拉链操作会进行默认值填充操作
val num7 = List(1,2,3,4)
val name = List("hadoop","Scala","Spark")
//此时使用zip 让num7 zip name 因为name 长度短,会以它为基准,多余数据会被删除
//为了减少数据丢失,可以以zipAll的形式来操作数据
//num7中存储的是整数,数据类型是Int,所以提供的整数默认值是 0
val defaultNum = 0
//name中存储的是字符串,数据类型是String,提供字符串的默认值“_”
val defaultStr = "_"
val list = num7.zipAll(name,defaultNum,defaultStr)
println(list)
//zipWithIndex函数将元素与其对应所在位置索引值形成对偶(pair)元组
val name2 = List("hadoop","Scala","Spark","linux")
val list2 = name2.zipWithIndex
println(list2)
//zip操作参数版本,如果需要从指定参数索引值开始指定拉链操作数据
val list3 = name2.zip(Stream from 1)
println(list3)
//unzip将已经执行zip操作之后的数据分成原有数据
val num8 = Seq(1,2,3,4)
val num9 = Seq(5,6,7,8)
val num1_1 = num8 zip num9
println(num1_1)
//拆分zip操作结果集
val unzip = num1_1.unzip
val value = unzip._1
映射(Map)
//scala中提供的集合默认都是不可以变的
val score =Map("kg"->50,"bb"->18,"bz"->60)
val score1 =Map(("kg",50),("kb",18),("uz",67))
//提供可变集合存储数据形式是一样的
val score2 =scala.collection.mutable.Map(("kg",50),("db",18),("fz",67))
//获取集合中的数据
/*
方式一:map集合名字+key名字 就可以得到value值--》map集合名字(key名)
如果key值存在 则返回数据,不存在则抛出异常
*/
val age = score("kg")
print(age)
/*
val age2 = score("kfg")
print(age2)
*/
/*
方式二:可以利用map集合中提供的 contains 方法判断是否存在key 如果存在则获取 不存在则返回默认值
*/
val age2 = if(score.contains("bb")) score("bb") else 0
/*
方式三:使用map集合中的get方法获取对应的key的value
get方法的返回值是option类型【含有some(有值)和none(没值)】
如果存在some值需要再次使用get方法进行获取才可以获取真正操作数据,否则无法操作 None如果执行get方法会出现异常
*/
val age3 = score.get("bg")
//val value = age3.get
val i = age3.getOrElse(0)
//最终版本:就是直接利用map集合中提供getOrElse 进行操作
// 如果key存在则获取value值 如果key不存在 则获取方法默认值
val age4 = score2.getOrElse("kg",0)
Map集合的基础操作
//创建一个可变Map集合
import scala.collection.mutable.Map
val score = Map("kg" -> 50, "bb" -> 18, "bz" -> 60)
//更新某个key的value
score.update("kg", 100)
//向map集合中添加数据
score("sz") = 120
//利用 += 一次性向map集合中添加一个或多个数据
score += ("ds" -> 1000)
score += ("ds" -> 1000, "fs" -> 89)
//添加另外一个集合中数据到map中 ++=
val score2 = Map("kg" -> 50, "db" -> 18, "gz" -> 60)
score ++= score2
//'-=' 删除kv键值对(一个或多个)'--=' 集合提供key的形式删除kv键值对(多个)
score -= "db"
score -= ("kg", "gz")
score --= List("kg", "gz", "db")
println(score)
遍历map
//遍历Map集合操作
//1.获取所有的key值,返回值是一个迭代器对象就可以获取数据
val keys: Iterable[String] = score.keys
for (key <- keys) {
println(key)
}
//2.获取所有value值,返回值是一个迭代器遍历迭代器对象就可以获取数据
val values: Iterable[Int] = score.values
for (value <- values) {
println(value)
}
//3.直接遍历map集合获取到数据是完整kv键值对(二元组)
for (ele <- score) {
println(ele)
//4、遍历的时候单独的获取k和v
for ((k, v) <- score) {
println("key值:" + k + "value值:" + v)
}
//5、foreach的遍历方式
score.foreach((k) => println(k._1 + k._2)) //使用foreach遍历map之后将map集合中数据看做了((key , value) , ( key, value))
列表(List)
元素类型必须相同 有序 列表是不可变的,内容及长度都不可变。
//构建list集合
//创建一个空集合
val empty = Nil//代表空集合
val empty2 = List()
//存储数据list集合
val names = List("kaige","bb","bz")
//List集合中存储其他集合的对象
val moreList = List(List(1,2,3),List(4,5,6))
//如果访问集合中数据--》 存在下标的 可以访问下标的形式来访问集合中的数据
print(names(0))
//List集合的遍历
for(ele <- names){
println(ele)
}
//foreach高阶函数的处理
names.foreach(name=>println(name))
names.foreach(println(_))
names.foreach(println)
//操作集合中数据使用map方法操作集合中数据并返回一个处理之后的新的集合
val ints = names.map(str => str.length)
val ints1 = names.map(_.length)
//向list集合中添加数据
val list = List(1,2,3)
//中缀符操作
val list2 = 0 :: list//向集合中第一个位置添加 0 数据
val list3 = list.:: (0)
val list4 = 0 +: list//还可以list.+:(0)
//追加集合的末尾
val ints2 = list :+ 4
//追加其他集合数据
val list1 = List(4,5,6)
val ints3 = list ++ list1//++: .:::
//List常用方法和基本操作
val list5 = List(1,233,3)
val list6 = List(4,33,5)
//获取列表中第一个元素
val head:Int = list5.head
//返回除第一个元素之外剩余List集合中元素————》返回的是一个集合
val tail = list5.tail
//判断集合是否为空 true-空 false-不空
val empty1 = list5.isEmpty
//拼接两个集合并生成一个新集合
val ints4=List.concat(list5,list6)
//将集合中数据进行反转(配合sorted进行降序操作)
val reverse = list5.reverse
//获取集合中长度
val length = list5.length
//获取集合中最后一个元素
val last = list5.last
//比较重要的方法 将来可以用作TopN
//获取列表中前N个元素
val ints5 = list5.take(2)//***
//丢弃列表的前N个元素获取剩余的元素
val ints6 = list5.drop(2)
//list集合支持拉链操作
val tuples = list5 zip list6
List的高阶方法***
//***(开发中常用)存在一定的通用性
val list1 =List(1,2,3,4)
/*
map函数:可以将集合中的每一个元素获取出来并提供逻辑进行计算返回一个处理之后的结果集
//将list集合中数据都乘以2返回计算之后的结果
*/
//根据map函数中参数提供 函数类型进行函数的定义
val num = (x:Int) => x*2
//将定义好的函数传递到map函数的参数中提供使用以完成数据操作
val ints : List[Int] = list1.map(num)
//Scala“简洁”进行开发利用ScaLa中提供高级函数中概念【匿名函数】的方式针对map方法参数进行函数赋值
val ints1: List[Int] = list1.map((x: Int) => x * 2)
//"简洁" 进行匿名函数实现 根据Scala自动推断已经得到 参数数据类型 所以无需定义直接提供参数即可
val ints2: List[Int] = list1.map(x => x * 2)
//“简洁”Scala在提供函数是现实如果遇到相同的类型的复数定义 可以省略参数名使用【_】进行简化操作
val ints3: List[Int] = list1.map(_ * 2)
/*
flatMap方法:扁平化处理,将集合中存储集合数据扁平化处理成一个List集合
Ps: flatMap这个方法时有两个方法简化而来flatten和 map
flatten这个方法就是扁平化处理可以将结合中数据处理完成为一个新的集合
*/
val list2:List[List[Int]] = List(List(1,2,3,4),List(5,6,7,8));
/*
将存储在List2集合中数据进行获取组合成一个新的集合,集合中存储不在是集合对象,而是具体数据值
这个过程称之为扁平化处理”---》List(List(1,2,3,4),List(5,6,7,8))
转换为---》List(1,2,3,4,5,6,7,8)
*/
val flatten = list2.flatten
println(flatten)
val line = List("hello tom hello jerry" , "hello xiaobai hello");
/*
需要将List集合中存储字符串进行处理获取字符串中每一个单词
形成一个List集合--》List( "helLo" , "tom" , "helLo" , "jerry" , . ..)
*/
//数据处理第一步:将字符串拆分为单词
val stringses: List[Array[String]] = line.map(_.split(" "))
//当前的数据形成--》list((Array("helLo" , "tom" ,...),Array( "helLo" , "jerry" , . ..)
//第二步:将存储在集合中数据进行扁平化处理
val flatten1: List[String] = stringses.flatten
//Scala为了方便我们操作就将flatten和map进行了结合 flatmap 遍历数据同时进行扁平化处理
// 上面操作直接简化为
val line2 = List("hello tom hello jerry" , "hello xiaobai hello" )
val strings: List[String] = line2.flatMap(_.split(" "))
/*
foreach方法:提供一个函数获取集合中每一个数据并执行打印操作
foreach与map方法的区别在于
foreach没有返回值(只适用于打印)
map有返回值(适合处理集合中数据并返回结果)
*/
list1.foreach(println)
/*
filter方法:提供一个函数获取集合中每一个数据 并在函数中提供数据的判断操作(提供booLean表达式判断),
如果返回值为true,则该元素返回一个存储数据结果的List集合
*/
//获取list1中所有的偶数
val ints4 = list1.filter(x => x % 2 == 0)
//简化:list1.filter(_%2==0)
/*
partition方法:提供一个函数获取集合中每一个数据 参与到参数中提供boolean表达式进行判断,
返回true值放置到一组 返回false值的放置到一组
*/
//需求:将List1中数据按照奇偶数据进行分组
val tuple: (List[Int],List[Int]) = list1.partition(_ % 2 == 0)
/*
find方法:提供一个函数获取集合中每一个元素 参与到参数中提供boolean表达式进行判断
获取到满足条件的【第一个元素】(第一个结果为true值直接返回,后续不在判断)
如果判断结果为false则返回None
PS: find方法的返回值是Option类型 所以找到数据以some(数据)返回,如果找不到以None返回
*/
val maybeInt = list1.find(_ % 2 == 0)
//保证安全
val i = maybeInt.getOrElse(0)
print(i)
/*
takewhile方法:提供一个函数获取集合中每一个元素 参与到参数中提供boolean表达式进行判断
一旦有一个元素不满足判断条件(即结果为false),后续的元素就不在判断了
直接返回存储结果的集合
PS:takewhile也可以过滤数据但是和filter是有很大区别
*/
val list3 = List(1,23,3,5,6,7)
val ints5 = list3.takeWhile(_ < 3)
println(ints5)
/*
droplwhile方法:提供一个函数获取集合中每一个元素 参与到参数中提供boolean表达式进行判断
一旦有一个元素不满足判断条件(即结果为false),后续元素就不在判断
之前判断结果为true的数据将被删除,为false这个数据开始剩余数据保留返回为集合
*/
val list4 = List(1,23,3,5,6,7)
val ints6 = list4.dropWhile(_ < 3)
println(ints6)
/*
span方法:提供一个函数获取集合中每一个元素 参与到参数中提供boolean表达式进行判断
判断条件为true的放置到一组,判断条件为false放置到一组
与partition是不同,span等同于是在做(c takewhile p, c dropwhile p)
但是它效率更高
*/
val tuple1 = list1.span(_ < 3)
/*
exists方法:提供一个函数获取集合中每一个元素 参与到参数中提供boolean表达式进行判断
判断的是否满足条件返回是true满足条件﹐false是不满足条件
判断集合中是否存在执行的元素值
ps:这个方法已经被contains替换了,参数不在需要提供boolean类型表达式直接提供判断是否存在数据即可
*/
val bool = list1.contains(1)
/*
forall方法提供一个函数获取集合中每一个元素 参与到参数中提供booLean表达式进行判断
这个方法判断集合中所有的数据是否满足条件,
只有所有数据都满足条件才会返回true 只要任何一个不满足直接返回false
*/
val list5 = List(1,2,334,6,6,4,7)
list5.forall(_ > 0)
/*
sortwith方法:这个一个排序方法可以提供排序数据
方式(函数)进行升序不是降序排序 类似于Javacomparator与Comparable接口的实现来执行排序方式
第一个参数>第二个参数 降序
第一个参数<第二个参数 升序
返回排序好之后的集合
*/
val list6 = List(1,3,5,7,3,3,3,2,62,6,9)
val ints7 = list6.sortWith(_ < _)
可变列表ListBuffer
ListBuffer与List的区别在于:修改ListBuffer改变的是本身。
//使用ListBuffer需要导入可变包
import scala.collection.mutable.ListBuffer
//创建一个可变ListBuffer并初始化3个数据
val list1 = ListBuffer[Int](1,2,3);
//创建一个可变ListBuffer空的集合
val list2 = new ListBuffer[Int]
//向list2中追加数据 ps:没有生成新的集合
list2 += 4;
list1.append(4)//append方法时一个可变参数可以追加一个或多个
//list1和list2两个集合,合并乘一个新ListBuffer集合 ps:生成了一个新的集合
val list3 = list2 ++ list1;
//将元素追加到list1的后面生成一个新的集合
val listBuffer = list1 :+ 5
//将可变与不可变集合之间进行转换操作
val buffer = ListBuffer(1,2,3,4)
val list = List(5,6,7,8);
//将可变集合转变为不可变集合
val list4 = buffer.toList
//将不可变集转变为可变集合
val buffer1 = list.toBuffer
Set
set中的元素不可重复,无序
//set集合的基础操作
val set1 = Set(5,2,7,6,8,7,3,1,9,2,7)
val set2 = Set(5,2,7,6,8,7,3,1,9,2,7)
//判断集合中是否存在指定元素
val bool = set1.contains(5)
//set集合提供了 交集 差集 并集的计算
//交集
val ints = set1 & set2
val ints1 = set1.intersect(set2)
//差集
val ints2 = set1 &~ set2
val ints3 = set1.diff(set2)
//并集
val ints4 = set1.union(set2)
/*
size 获取集合中存储元素个数
splitAt:将集合拆分成两个容器,第一个容器由前n(方法参数)个元素组成
第二个容器由剩余元素组成
take 返回前N(方法参数)个元素
toXXX方法可以转换其他集合存储数据
*/
集合的重要函数
高阶函数
//聚合函数
//sum
//reduce,对集合中的数据进行计算操作
val list = List(1,2,4,5,6,7,89,90)
println(list.sum)
//reduce求和计算
/*
执行流程:对两个变量获取集合中第一个和第二个元素
执行x+y 得出结果
触发计算逻辑x不在获取集合中的元素,而是得到上一次x+y的结果值
y继续获取集合中数据 参与x+y计算 直到y无法获取集合中数据时,整个reduce计算结束
*/
val sum = list.reduce((x: Int, y: Int) => x + y)
//val sum = list.reduce(_ + _)
println(sum)
//reduce方法有两个变种:reduceleft和reduceright 在没有开起并行化的前提下,他们的计算逻辑方式都是一样
//如果开启并行化reduceleft reduceright 会强制要求计算操作 要求是从左往右 从右往左
//fold函数进行求和计算
/*
fold 是典型的柯里化,需要两个参数
第一个参数:第一个小括号 提供默认值 会参与就算
第二个参数:第二个小括号 提供计算逻辑
执行流程:x获取到0这个值,y获取到集合中第一个元素
执行x+y的逻辑 得到第一次计算结果 x获取x+y y依旧获取集合中每一个元素参与计算
*/
list.fold(0)((x:Int,y:Int)=>x+y)
//fold方法有两个变种:foldleft和foldright 在没有开起并行化的前提下,他们的计算逻辑方式都是一样
//如果开启并行化foldleft和foldright 会强制要求计算操作 要求是从左往右 从右往左
//将每个元素*2
def method(x:Int):Int = {
x*2
}
def main(args: Array[String]): Unit = {
val list =List(1,2,3,4,5,6)
//将集合中的每一个元素*2返回最终结果 将方法转换为函数
//手动 方法名 _ 方法传递到一个函数的参数位进行赋值,自动将方法转换为函数
val list1 = list.map(method)
println(list1)
}
//将函数作为方法的返回值存在,通过调用方法的得到另外一个函数操作
def main(args: Array[String]): Unit = {
def urlBuilder(ssl:Boolean,domainName:String):(String,String)=>String = {
val schema = if(ssl)"https//" else "http://"
(endPoint:String,query:String)=>s"$schema$domainName/$endPoint?$query"
}
val domainName ="www.qfedu.com"
val function = urlBuilder(ssl = true, domainName)
val url = function("user","id=1")
println(url)
/*
java角度理解
class Person{}
class Demo{
public static Person showPerson(){
return new Person()
}
psvm
Person p = showPerson()
sout(p)
p.getAge()
}
*/
}
/*
高阶函数:允许函数提供参数类型是【函数类型】 允许函数的返回值类型是【函数类型】
*/
def func(x:Int):(Int)=>Int={
(y:Int)=>x+y
}
val func_1:(Int)=>Int = func(1)
val sum = func_1(2)
//简化操作提供的概念
def func2(x:Int)(y:Int):Int ={
x+y
}
//触发柯里化方法时-->第二个参数(2)等价与触发第一个函数执行 (y:Int)=>x+y
val sum2 = func2(1)(2)
柯里化
Curring函数,指的是,将原来接收两个参数的一个函数,转换为两个函数,第一个函数接收原先的第一个参数,然后返回接收原先第二个参数的第二个函数。
在函数调用的过程中,就变为了两个函数连续调用的形式
即柯里化(Currying)是指将原先接受多个参数的函数多个一个参数的多参数列表的过程。
/*
使用柯里化目的在于让传递匿名函数作为参数的语法更加简洁
柯里化可以更加简便的进行 函数作为返回值操作
如果将一个方法的返回值 定义为一个函数
调用方法时是获取获取到这个函数,只有再次代用这个函数才可以得到具体的结果
需要调用两次才可以,但是利用柯里化可以简化这个调用直接得到结果值
*/
//简化函数作为返回值时的调用执行过程
def func(x: Int): (Int) => Int = {
(y: Int) => x + y;
}
//第一次调用这个方法时,得到结果不是一个具体数据,而是一个函数即(y:Int) => x+y
val func_1: Int => Int = func(1)
//第二次func_1才可以得到最终的计算结果
val sum = func_1(1);
println(sum)
//利用柯里化简化这个操作,直接得到计算结果
def func2(x:Int)(y:Int)={
x+y;
}
val sum2 = func2(1)(1);//第二个(1)等价在触发 (y: Int) => x + y;
//使用柯里化让传递匿名函数作为参数的语法更为简洁
//需求:编写一个泛型方法,用来完成两个值类型的计算(具体的计算封装到函数中)
//没有使用柯里化方式定义方法
def curringMethod1[A <: AnyVal](x:A,y:A,f:(A,A)=>A)={
f(x,y)
}
//使用了柯里化定义方法
def curringMethod2[A <: AnyVal](x:A,y:A)(f:(A,A)=>A)={
f(x,y)
}
//没有提供柯里化方法在传递匿名函数是不可以使用 简化操作必须完整定义出函数
curringMethod1(1,2,(x:Int,y:Int)=>x+y);
/*
不能提供简化操作 因为方法中使用泛型,需要提供数据类型才可以进行泛型赋值操作
如果使用简化的匿名函数进行推断是无法正确推断出数据类型
*/
//curringMethod1(1,2,_+_);
//使用了提供柯里化操作的方法就可以利用简化操作
/*
第一个(1,2)已经推断出了泛型是Int类型,然后在调用第二(_+_)这个函数操作
此时根据第一个推断出结果是Int类型,所以简化操作也推断出是Int类型
*/
curringMethod2(1,2)(_+_);