Scala 函数、Scala 集合
Scala函数
面向对象编程和面向函数编程
Scala中函数的定义
函数类型的定义
函数的简写
lambda表达式 --- 匿名函数
package com.shujia.scala
object Demo14Fun1 {
def main(args: Array[String]): Unit = {
/**
* 面向对象编程 : 将对象传来传去
* 1、将对象作为参数
* 2、将对象作为返回值
*
* 需要明确对象的类型
*
*
* 面向函数编程 : 将函数传来传去
* 1、可以将一个函数作为参数
* 2、可以将一个函数作为返回值
*
* 所以需要明确每一个函数的类型
*
*/
/**
* scala中函数的定义
* 1、可以在object创建 : 通过对象名直接调用
* 2、可以类中创建 : 需要创建类的对象才能调用
* 3、可以在任何代码块中创建 : 可以直接在后面调用
*
* 函数的基本要素
* 1、函数名
* 2、函数的参数列表
* 3、函数的返回值
* 4、函数体
*
* 使用函数的时候,要注意函数的作用域
*
* 在同一个代码块中不能出现同名的函数
*/
def fun1(): Unit = {
println("fun1")
}
//调用函数、函数可以多次调用
fun1()
fun1()
/**
* 函数类型的定义
* 1、函数的类型 与 函数的 参数 和 返回值 有关
*
*
* def add(i: Int): Int = {
* i + 1
* }
* 函数类型的描述: 这是一个参数为Int类型返回值为Int类型的函数
*
* 函数类型的表示方式: Int => Int
*
*/
def add(i: Int): Int = {
i + 1
}
val j: Int = add(100)
println(j)
//这是一个参数为String 返回值为Int类型的函数
def fun2(str: String): Int = {
str.toInt
}
//这是一个参数为String没有返回值的函数
def fun3(str: String): Unit = {
println(str)
}
/**
*
* 函数的简写
* 1、如果函数体只有一行 {} 可以省略
* 2、如果最后一行作为返回值return可以省略
* 3、如果没有参数,() 可以省略
* 4、返回值类型可以省略,会自动推断
*
*/
def fun4(str: String): Unit = println(str)
/**
* lambda表达式 --- 匿名函数
*
* (str: String) => str.toInt
*
* => : 左边是参数
* => : 右边是函数体
*
*/
// 这是一个参数为String 返回值为Int类型的函数
// 这相当于用一个变量来接收 lambda 表达式(匿名函数)
// 注意 : String => Int 和 (str: String) => str.toInt
// String => Int -- 描述函数类型
// (str: String) => str.toInt -- lambda 表达式
val fun5: String => Int = (str: String) => str.toInt
// 在代码块中,直接调用
val k: Int = fun5("10004")
println(k)
def fun6(i: Int): Int = {
i * 100
}
//函数的调用
val i2: Int = fun6(1000)
//将函数赋值给一个变量
val f7: Int => Int = fun6
}
}
函数的应用
以函数作为参数 --重点
以函数作为参数的简写
以函数作为参数的应用
foreach 函数
package com.shujia.scala
object Demo15Fun2 {
def main(args: Array[String]): Unit = {
/**
* 函数的应用
*
* 高阶函数
*
* 1、以函数作为参数 --重点
* 2、以函数作为返回值
*
*/
/**
*
* 以函数作为参数
*
* f: 是一个参数为String 返回值为Int类型的函数
*
* fun1 是什么类型的函数?
* fun1是一个参数为f 没有返回值的函数
*
*/
def fun1(f: String => Int): Unit = {
// 调用传进来的函数
val i: Int = f("100")
println(i)
}
// 一个参数为String 返回值为Int类型的函数
def f1(str: String): Int = {
str.toInt
}
// 调用fun1() 需要传入一个参数为String 返回值为Int类型的函数
fun1(f1)
// 这边传入不同的函数、仔细体会面向函数编程的思想
def f2(str: String): Int = {
(str + "1232123").toInt
}
fun1(f2)
/**
* 使用 lambda 作为参数
* 就是匿名函数的传递
*/
fun1((s: String) => {
val i: Int = s.toInt
//最后一行作为返回值
i
})
/**
* 上面的简写
* lambda 表达式的简写
*/
// 1、如果代码只有一行括号可以省略
fun1((s: String) => s.toInt)
// 2、lambda 的参数类型可以省略
// lambda 表达式参数的类型会自动推断
fun1(s => s.toInt)
// 3、如果lambda的参数只使用了一次可以使用下划线代替
fun1(_.toInt)
println("=" * 100)
/**
* 以函数作为参数的应用
*
*/
val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
/**
* foreach : 遍历数组中的元素, 并将 遍历出来的元素 作为参数 传递给 作为参数传入 foreach 括号中的函数
*
* foreach 将循环之后需要做的处理交给调用者,由调用者传入一个函数进去处理
*/
arr.foreach((i: Int) => {
println(i)
})
println("=" * 100)
//简写
arr.foreach(i => println(i))
arr.foreach(println(_))
println("=" * 100)
/**
* println 是一个参数为Any 没有返回值的函数
*
* arr.foreach 需要的是参数为Int 没有返回值的函数
*
* scala函数的调用也符合多态的思想
*
*/
arr.foreach(println)
}
}
以函数作为返回值 -- 不常用
调用返回的函数并简化调用过程
函数柯里化
package com.shujia.scala
object Demo16Fun3 {
def main(args: Array[String]): Unit = {
/**
* 以函数作为返回值 -- 不常用
*
*/
// fun1 是一个 参数为 String 返回值为 一个 参数为 String 返回值为 Int 的函数
def fun1(str: String): String => Int = {
def f(s: String): Int = {
(s + str).toInt
}
// 返回一个函数
f
}
// 调用fun1 返回一个函数,并用变量f2接收
// 所以f2是一个 参数为String 返回值为Int 的函数
val f2: String => Int = fun1("123213")
//调用返回的函数
val i: Int = f2("222")
println(i)
// 简化调用过程
// fun1("111") -- 相当于上面的 f2
// fun1("111")("222") -- 相当于 f2("222")
val j: Int = fun1("111")("222")
// 上面 fun1 函数的改写 不要函数的返回值是一个函数
def fun3(str: String, s: String): Int = {
(s + str).toInt
}
val k: Int = fun3("333", "444")
/**
* 上面 fun1 函数的简写
*
* 这里并不是上面 fun3 函数那样将 fun1 函数改写
*
* 函数柯里化
*
*/
def fun2(str: String)(s: String): Int = {
(s + str).toInt
}
// 可以一次性给两个函数传参
val i2: Int = fun2("555")("6666")
println(i2)
/**
* 也可以先给第一个函数传参 再 给后面的函数传参
*/
val f4: String => Int = fun2("777")
val i4: Int = f4("888")
val i5: Int = f4("999")
}
}
一个函数的参数和返回值都是一个函数的情况
package com.shujia.scala
object Demo17Fun4 {
def main(args: Array[String]): Unit = {
/**
* 参数和返回值都是一个函数
*
*/
def fun1(f: String => String): String => String = {
f
}
// 这里用变量接收一下 fun1 观察一下 fun1 的类型
// val f: (String => String) => String => String = fun1
// 调用 fun1
val f1: String => String = fun1((s: String) => s)
val str: String = f1("shujia")
println(str)
}
}
map 函数
package com.shujia.scala
object Demo18Fun5 {
def main(args: Array[String]): Unit = {
val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
/**
* 将arr中的数据都加2
*
*/
var i = 0
while (i < arr.length) {
arr(i) = arr(i) + 2
i += 1
}
arr.foreach(println)
println("=" * 100)
/**
*
* map: 将数组中的元素遍历并传递给后面的函数
* map会将后面的函数的返回值构建成一个新的数组
* 返回一个新的数组
*
*/
val arr2: Array[Int] = arr.map((i: Int) => i + 2)
arr2.foreach(println)
println("=" * 100)
/**
* 将数组中的元素奇数加1,偶数乘以2
*
*/
val arr3: Array[Int] = arr.map((i: Int) => {
if (i % 2 == 1) {
i + 1
} else {
i * 2
}
})
arr3.foreach(println)
}
}
Scala 集合
list
package com.shujia.scala
import java.util
import scala.collection.mutable.ListBuffer
import scala.io.Source
object Demo19List {
def main(args: Array[String]): Unit = {
/**
* list : 有序不唯一
* set : 无序唯一
* map : k-v结构
* tuple: 固定长度的集合
*
*/
/**
* 不可变 list -- 不能增删元素
* 底层是数组
* scala中的list 提供了很多实用的方法
*/
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 1)
println(list.head) //获取第一个元素
println(list.tail) //获取不包含第一个元素的所有元素
println(list.last) //获取最后一个
println(list.take(3)) //从左边取3个
println(list.takeRight(3)) //从右边取3个
println(list(2)) //通过下标获取元素
//和split功能相反
println(list.mkString("|")) //通过一个分隔符将集合拼接成一个字符串
println(list.sum) //求和
println(list.max) //获取最大值
println(list.min) //获取最小值
println(list.sum / list.length.toDouble) //平均值
println(list.distinct) //去重 返回一个新的集合
println(list.reverse) //反转集合 返回一个新的集合
println(list.drop(1)) //从左向右删除一个元素 返回一个新的集合并不改变原集合
println(list)
/**
* 高级的方法
*
*/
/**
* foreach: 遍历集合中元素,并将元素一个一个传递给后面的函数
*
*/
var sum = 0
list.foreach(i => {
sum += i
})
println(sum)
/**
* map : 遍历集合中的元素并将元素一个一个传递给后面的函数,最后将后面函数的返回值构建成一个新的集合返回
*
*/
val list2: List[Int] = list.map((i: Int) => i + 2)
println(list2)
//改变集合中所有元素的类型
val strs: List[String] = list.map((i: Int) => i.toString)
println(strs)
/**
* sort
*
* sortBy: 通过一个字段进行排序, 默认是升序
*
*/
val sortList: List[Int] = list.sortBy((i: Int) => i)
println(sortList)
/**
* 读取学生数据,按照年龄排序
*
*/
//读取文件得到一个集合
val students: List[String] = Source.fromFile("data/students.txt").getLines().toList
//按年龄倒序排列
val studentSort: List[String] = students.sortBy((stu: String) => -stu.split(",")(2).toInt)
studentSort.foreach(println)
/**
*
* sortWith: 指定一个排序规则
*/
// (i: Int, j: Int) => i > j
// i 代表上一条数据 j 代表当前数据
val sortList2: List[Int] = list.sortWith((i: Int, j: Int) => i > j)
println(sortList2)
println("=" * 100)
val words = new util.ArrayList[String]()
val lines = List("java,spark", "java,hadoop", "java,scala,hive", "bhase,hadoop,scala")
for (line <- lines) {
val split: Array[String] = line.split(",")
for (word <- split) {
words.add(word)
}
}
println(words)
println("=" * 100)
/**
*
* 上面的逻辑可以用 flatMap 实现
* flatMap: 遍历集合中的元素并将之一个一个传递给后面的函数,传入一行返回多行
* flatMap 分两步
* 1、先遍历集合中的元素并将之一个一个传递给 将来当做参数传进 flatMap 的函数
* 2、将 将来当做参数传进 flatMap 的函数 返回的 结果 构建成一个新的集合,返回给调用者
*
*/
val words2: List[String] = lines.flatMap((line: String) => line.split(","))
println(words2)
println("=" * 100)
/**
* 可变list -- ListBuffer
*
*/
val listBuffer = new ListBuffer[String]()
//增加元素
listBuffer += "java"
//增加多个元素
listBuffer ++= List("scala", "hadoop", "java")
println(listBuffer)
//删除一个元素
listBuffer -= "java"
//删除多个元素
listBuffer --= List("hadoop", "scala")
println(listBuffer)
//通过下标修改元素
listBuffer.update(0, "hadoop")
println(listBuffer)
//通过下标删除元素
listBuffer.remove(0)
println(listBuffer)
}
}
set
package com.shujia.scala
import scala.collection.mutable
object Demo20Set {
def main(args: Array[String]): Unit = {
/**
* 不可变Set
*
*/
val set = Set(1, 2, 3, 4, 5, 6, 7, 8, 9, 1)
println(set)
println(set.head)
println(set.tail)
println(set.last)
println(set.sum)
println(set.max)
println(set.min)
/**
* 取出集合中的奇数
*
* filter : 遍历集合中的元素并将之一个一个传递给 将来当做参数传进filter的函数 , 被当做参数传进来的函数返回true保留数据,返回false过滤数据
*
*/
val filterSet: Set[Int] = set.filter((i: Int) => i % 2 == 1)
println(filterSet)
val s1 = Set(1, 2, 3, 4, 5, 6)
val s2 = Set(3, 4, 5, 6, 7, 8, 9)
println(s1 & s2) //交集
println(s1 | s2) //并集
println(s1 &~ s2) //差集
/**
* list set map array 都有以下方法
* map
* flatMap
* filter
* foreach
* groupBy
*
* set 集合不能排序, set map 不能反转
*/
/**
* 可变Set -- mutable.HashSet
* mutable -- 可变
* imutable -- 不可变
*/
// 因为有 伴生对象、apply方法 所以不用 new 也行
// val hashSet = mutable.HashSet()
val hashSet = new mutable.HashSet[String]()
//增加元素
// += 和 add 是一样的
hashSet.add("java")
hashSet += "scala"
println(hashSet)
//移除元素
// -= 和 remove 是一样的
hashSet.remove("java")
hashSet -= "scala"
println(hashSet)
//可变集合转换成不可变集合
//只要涉及到转化 就是 to
val set2: Set[String] = hashSet.toSet
}
}
tuple
package com.shujia.scala
object Demo21Tuple {
def main(args: Array[String]): Unit = {
/**
* 元组 -- 元组是不可变的
* 可以通过下标获取元素
* 相比较数组不会出现下标越界的问题
* 元组中的类型没有限制,每个元素的类型都是独立的
* 元组最多只能存放22个元素
*/
// Tuple7 -- 表示含有7个元素的元组,可以省略,Scala会自动推断
// 这个元组 可以称为 7元组
val tuple = Tuple7(1, 2, 3, 4, 5, 6, "asd")
println(tuple._7)
//简写
val t2 = (1, 2, 3, 4)
println(t2)
//可以通过多个变量接收
//(id, name, age) 这个代表定义多个变量一起接收这个元组
val (id, name, age) = ("001", "张三", 23)
println(id)
println(name)
println(age)
}
}
map
package com.shujia.scala
import scala.collection.{immutable, mutable}
object Demo22Map {
def main(args: Array[String]): Unit = {
/**
* 不可变 map
* Map 需要传入 k-v 使用二元组构建 k-v
* "003" -> "王五" 构建二元组的简写
*/
val map = Map(("001", "张三"), ("002", "李四"), "003" -> "王五")
println(map)
//通过key 获取value
println(map("003"))
//如果 key 存在返回 value 如果 key 不存在返回后面的默认值
println(map.getOrElse("001", "默认值"))
/**
* Map 集合的map方法 传给 将来当做参数传进map()的函数 的参数是一个二元组,可以通过下标获取key和value
*
*/
val values = map.map((kv: (String, String)) => kv._2)
println(values)
//获取key和value
println(map.values)
println(map.keys)
//遍历map
map.foreach(println)
/**
* 可变的map -- mutable.HashMap
*
*/
val hashMap = new mutable.HashMap[String, String]()
//保存元素
hashMap.put("001", "张三")
hashMap.+=(("002", "李四"))
hashMap += "003" -> "王五"
println(hashMap)
//删除元素
hashMap.remove("001")
hashMap -= "002"
println(hashMap)
}
}