Scala 第一篇 基础篇

Scala 第一篇 基础篇

  • 一、变量与常量
    • 1、变量
    • 2、常量
  • 二、数据类型
    • 1、数据基本类型概览
    • 2、元组的声明与使用
    • 3、Range介绍和使用
    • 4、Option 类型的使用和设计
    • 5、类型别名
  • 三、运算符
  • 四、程序逻辑
    • 1、一切都是表达式
    • 2、分支语句
    • 3、循环语句
  • 五、集合
    • 1、List
    • 2、Set
    • 3、Map
    • 4、Array
  • 六、函数
    • 1、普通函数, 匿名函数
    • 2、高阶函数(重点)
    • 3、隐式参数,隐式函数
    • 4、偏函数
    • 5、总结
    • 6、补充:下划线 _ 用途。
  • 七、数组方法(重点)
    • 1、创建数组
    • 2、基本操作
    • 3、查找,定位
    • 4、数据拷贝,移植
    • 5、添加
    • 6、删除
    • 7、修改
    • 8、提取

一、变量与常量

1、变量

创建变量:必须赋初值
1、可以不指定变量的具体类型如 var a = 5,则变量的类型由【首次】赋值的值类型决定且锁定。
2、若声明时已指定变量类型如 var a:String = “”,则类型不可更改

var variableName[:Type] = V

2、常量

创建常量且初始化后,常量的类型和值都将锁定

val valName[:Type] = V

二、数据类型

1、数据基本类型概览

Any: 所有类型的超类(顶级类型)
AnyVal: 值类型的超类
AnyRef: 引用类型的超类
Unit: 无值,类似java中的void
Nothing: 所有类型的子类
Null: 表示null或空引用

在这里插入图片描述

2、元组的声明与使用

元组 TupleN[T1,…,TN] (复合类型)
T :泛型
N :1~22
():表示元组
元组类型表达:推荐 syntactic suger 语法糖
(String, Int) <=> Tuple2[String, Int]

二元组的声明和初始化

val tp2 = ("java", 88)	// 实际应用:最简语法
val tp2: (String, Int) = ("java", 88) // 初学推荐
val tp2: Tuple2[String,Int] = Tuple2("java", 88) //写全
val v1 = tp2._1		// 元组的使用,提取元组第一个值
val v2 = tp2._2
val it:Iterator[Any] = tp2.productIterator

注意:为避免冲突,须知()还可以表示:

  1. 数组下标提取 array(int)
  2. 方法的参数列表 method(p1,…,p2)

3、Range介绍和使用

Range 属于值类型的超类 AnyVal,表示一个连续的数字序列。
通过 to 方法或 until 方法创建

// >=1 && < 10
val r:Range = START until END by STEP 	// STEP缺省默认为1
val a:Range = 1 until 10 by 2			// 创建了一个半开范围,从 1 开始(包含 1),到 10 结束(不包含 10),步长为 2。
val r:Range = Range(start:Int,stop:Int,step:Int)// >=1 && <=10
val r:Range = START to END by STEP 		// STEP缺省默认为1
val a:Range.Inclusive = 1 to 10 by 2	// 创建了一个闭合范围,从 1 开始(包含 1),到 10 结束(包含 10),步长为 2。
val a:Range.Inclusive = Range.Inclusive(start:Int,stop:Int,step:Int)

4、Option 类型的使用和设计

Option 是 Scala 中用来表示可能包含值或者不包含值的容器类型。通常用于避免空指针异常,因为它要求显式地处理可能为空的情况。

val opt: Option[Int] = Some(10) //将 opt 设置为包含整数值 10 的 Some
val rst = opt.getOrElse(0)
//使用 getOrElse 方法从 opt 中获取值,如果 opt 是 Some,则返回其中的值(这里是 10),如果是 None,则返回指定的默认值(这里是 0)。

函数的设计利用 Scala 中的 Option 类型,以一种更安全和更函数式的方式处理可能为空的情况。通过返回 Option 类型,明确地表达了可能存在结果和不存在结果的两种可能性,从而避免空指针异常等问题。

def add(a:Int,b:Int):Option[Int] = {val sum = a + bif(sum>100){None}else{Some(sum)}
}

5、类型别名

简化复杂的类型名称

type S = String		//用S代表String
var str:S = "henry"

三、运算符

跟Java,C++等没什么区别

赋值运算符: 	= += -= *= /= %=
算术运算符: 	+ - * / %			没有 ++ --
关系运算符: 	> >= < <= == !=
逻辑运算符: 	&& || !

四、程序逻辑

1、一切都是表达式

val expr = {}		//声明时执行
lazy val expr = {}	//惰性表达式  使用时执行

惰性表达式举例

// 定义一个类,表示从数据库加载的数据
class DatabaseData {// 模拟从数据库加载数据的耗时操作println("Loading data from database...")// 假设这里是实际的加载数据操作// 这里只是简单地打印一条消息表示加载完成println("Data loaded.")
}// 创建一个对象,包含一个惰性求值的表达式
object Main {// 定义一个惰性求值的表达式,表示从数据库加载数据lazy val data = new DatabaseDatadef main(args: Array[String]): Unit = {println("Main method starts.")// 在主方法中使用数据println("Accessing data...")// 当访问 data 时,如果 data 还没有被初始化,则执行初始化操作println(data)// 再次访问 data,此时由于已经初始化过了,所以不会再次执行初始化操作println(data)println("Main method ends.")}
}

2、分支语句

if...else 语句
val x = 10
//正常写法
if (x > 10) {println("x 大于 10")
} else if (x < 10) {println("x 小于 10")
} else {println("x 等于 10")
}
//类三元运算符写法
val rst = if(x > 10) "x 大于 10" else "x 小于等于 10"
模式匹配(重点)

在 Scala 中,模式匹配中的条件守卫允许在模式匹配的基础上增加额外的条件判断。当模式匹配成功后,会检查守卫条件是否为真,只有条件为真时,才会执行相应的逻辑

  1. 数值

    val dial = Random.nextInt(4)
    val rst = dial match {case 0 => "余额"case 1 => "充值"case 2 => "活动"case 3 => "贷款"case _ => "未知"
    }
    
  2. 字符串与条件守卫

    val content = "123456@qq.com"
    val rst = content match {case a if a.matches("\\w+@\\w{2,}\\.(com|cn)") => "email"case a if a.matches("1[3-9]\\d{9}") => "handset"case "NULL" => "nothing"case _ => "unknown"
    }
    println(rst)	//输出:emailval day = "Monday"
    day match {case "Monday" => println("星期一")	//最后只调用此行输出:星期一case "Tuesday" => println("星期二")case "Wednesday" => println("星期三")case _ if day.startsWith("T") => println("星期二到星期五")case _ => println("其他")
    }
    
  3. 元组

    val rst = (7,101) match {case (3,_) => (3,1)case (5,a) => if(a%2==0) (5,0) else (5,1)case _ => (0,0)
    }
    
  4. 列表

    val rst = List(1,"hive",88) match {case List(id,"java",score:Int) => if(score>=60) ("java","pass") else ("java","fail")case _ => ("SKIP","NONE")
    }
    
  5. 类型

    val rst = value match {case a:Int => ("int",a)case a:(Int,Int) => ("Tuple2",a)case a:String => ("String",a)case _ => ("Unknown",1)
    }
    
  6. 嵌套

    val rst = (1,("java",67)) match {case (1,(sub:String,score:Int)) => (sub,score)case _ => ("UnknownFormat",1)
    }
    

3、循环语句

while循环
var i = 0
while (i < 5) {println(s"当前的值为: $i")i += 1
}
do while循环
var j = 0
do {println(s"当前的值为: $j")j += 1
} while (j < 5)
for 循环

有多种不同的用法和语法糖

// 基本的 for 循环
for (i <- 0 until 5) {println(s"当前的值为: $i")
}// 带有条件的 for 循环
for (i <- 0 until 10 if i % 2 == 0) {println(s"偶数值为: $i")
}// 嵌套的 for 循环
for (i <- 0 to 2; j <- 0 to 2) {println(s"($i, $j)")
}

五、集合

scala 支持运算符的重载
immutable 不可变集合包,mutable 可变集合包
默认导入不可变集合包
使用可变集合需要先import scala.collection.mutable,再通过 mutable.T 使用
常用集合:List、Set、Map、Array

import scala.collection.immutable.Set						// 导入具体类
import scala.collection.mutable._							// 导入包内所有类
import scala.collection.mutable.{ListBuffer,ArrayBuffer}	// 导入包内部分类

1、List

import scala.collection.immutable.List
import scala.collection.mutable.LiscalastBuffer //可以代替链表高效插删

List分组体验代码

val list = List(1, 2, 3, 4, 5, 6, 7)val it: Iterator[List[Int]] = list.grouped(3)
println("按3个分组")
it.foreach(println)println("滑动窗口,步长1")
val it2 = list.sliding(3, 1)
it2.foreach(println)println("滑动窗口,步长2")
val it3 = list.sliding(3, 2)
it3.foreach(println)println("排列组合,不考虑顺序问题")
val it4 = list.combinations(3)
it4.foreach(println)println("分组,按模2不同分组")
val map = list.groupBy(a => a % 2)
map.foreach(println)println("是否大于3分组")
val map2 = list.groupBy(a => a > 3)
map2.foreach(println)

输出结果

3个分组
List(1, 2, 3)
List(4, 5, 6)
List(7)
滑动窗口,步长1
List(1, 2, 3)
List(2, 3, 4)
List(3, 4, 5)
List(4, 5, 6)
List(5, 6, 7)
滑动窗口,步长2
List(1, 2, 3)
List(3, 4, 5)
List(5, 6, 7)
排列组合,不考虑顺序问题
List(1, 2, 3)
List(1, 2, 4)
List(1, 2, 5)
List(1, 2, 6)
List(1, 2, 7)
List(1, 3, 4)
List(1, 3, 5)
List(1, 3, 6)
List(1, 3, 7)
List(1, 4, 5)
List(1, 4, 6)
List(1, 4, 7)
List(1, 5, 6)
List(1, 5, 7)
List(1, 6, 7)
List(2, 3, 4)
List(2, 3, 5)
List(2, 3, 6)
List(2, 3, 7)
List(2, 4, 5)
List(2, 4, 6)
List(2, 4, 7)
List(2, 5, 6)
List(2, 5, 7)
List(2, 6, 7)
List(3, 4, 5)
List(3, 4, 6)
List(3, 4, 7)
List(3, 5, 6)
List(3, 5, 7)
List(3, 6, 7)
List(4, 5, 6)
List(4, 5, 7)
List(4, 6, 7)
List(5, 6, 7)
分组,按模2不同分组scala
(1,List(1, 3, 5, 7))
(0,List(2, 4, 6))
是否大于3分组
(false,List(1, 2, 3))
(true,List(4, 5, 6, 7))

2、Set

import scala.collection.immutable.Set
import scala.collection.mutable.Set

Set 体验差&~、交&、并| 代码

// 可变集合
val set1 =  mutable.Set(1, 2, 3)
val set2 = mutable.Set(3, 4, 5)
// 不可变集合
val set3 = Set(3, 4, 5, 6)println("交集")
val ints0 = set1 & set2      // 等价于set1.intersect(set2)
println(ints0)println("并集")
val ints1 = set1 | set2     // 等价于set1.union(set2)
println(ints1)println("差集")
val ints2 = set1 &~ set2    // 等价于set1.diff(set2)
println(ints2)scala// 差集,前后影响数据类型
val ints3: mutable.Set[Int] = set1 &~ set3
val ints4: Set[Int] = set3 &~ set1

输出结果

交集
Set(3)
并集
Set(1, 5, 2, 3, 4)
差集
Set(1, 2)

3、Map

import scala.collection.immutable.Map
import scala.collection.mutable.Map

Map体验 += -= ++ 代码

// 创建一个可变的 Map
var map = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)// 添加键值对
map += ("d" -> 1)
map += (("sss", 2), ("xxx", 3))
scala
// 移除键值对
map -= "sss"// 使用 ++ 添加另一个 Map
map ++= Map("e" -> 5, "f" -> 6)
scala
// 输出结果
println(map)

输出结果

Map(e -> 5, xxx -> 3, b -> 2, d -> 1, a -> 1, c -> 3, f -> 6)

4、Array

import scala.Array
import scala.collection.mutable.ArrayBuffer

Array体验 += -= ++ 代码

// 创建一个可变的数组缓冲
val buffer = ArrayBuffer(1, 2, 3)// 在尾部添加一个元素
buffer += 4// 移除指定位置的元素
buffer -= 2scala// 添加另一个数组缓冲的所有元素
buffer ++= ArrayBuffer(5, 6, 7)scala// 输出结果
println(buffer)

输出结果

ArrayBuffer(1, 3, 4, 5, 6, 7)

备注:Array 和 List 是两种不同的集合类型,区别如下

  1. 可变性
  • Array 是可变的,可以修改其元素的值,并且可以改变数组的长度。
  • List 是不可变的,一旦创建后,就不能修改其元素或长度。如果需要添加、删除或修改元素,可以通过创建新的 List 实例来实现。
  1. 实现方式
  • Array 在底层是通过 Java 数组来实现的,它提供了快速的随机访问(通过索引)和可变性。
  • List 则是使用链表(Linked List)来实现的,每个元素都连接到下一个元素,因此访问和修改操作的效率较低,但对于添加和删除元素来说更加高效。
  1. 类型
  • Array 是一个包含固定大小元素的集合,元素类型可以是任意类型,甚至可以是不同类型。
  • List 是一个包含有序元素的集合,元素的类型相同,并且列表的长度可以动态增长或缩减。

六、函数

1、普通函数, 匿名函数

普通函数:最常见的函数类型
匿名函数:也称为函数字面量或 Lambda 表达式,没有名称,直接定义在代码中

函数定义
// 普通函数 
def add(x: Int, y: Int): Int = {x + y
}
// 匿名函数
val add: (Int, Int) => Int = (x, y) => x + y
字符串插值函数

字符串插值函数属于 Scala 中的内置函数
字符串插值函数允许将变量、表达式或者其他字符串插入到字符串字面量中,形成一个新的字符串。
Scala 提供了三种常用的字符串插值函数

val str = s""			
val str = raw""			
val str = f""

s 插值器:用于字符串插值,允许在字符串中引用变量或表达式。

val name = "Alice"
val age = 30
val message = s"My name is $name and I am $age years old."
println(message)		// 输出:My name is Alice and I am 30 years old.

f 插值器:用于格式化字符串,类似于 C 语言中的 printf 函数。

val weight = 75.5
val bmi = f"$weight%.2f"
println(s"Your BMI is $bmi")	//输出:Your BMI is 75.50

raw 插值器:用于原始字符串,不会对字符串中的特殊字符进行转义。

val path = raw"C:\Users\node"
println(path)	//输出:C:\Users\node

2、高阶函数(重点)

接受函数作为参数或返回函数的函数。

def applyFunc(f: Int => Int, x: Int): Int = f(x)
柯里化函数

将多个参数列表转换为一系列函数调用,每次调用返回一个新的函数

def add(x: Int)(y: Int): Int = x + y

分析以下两个方法的区别

def func1(init:Int)(a:Int*):Int = init+a.sum 	// 函数作为返回类型
def func2(init:Int, a:Int*):Int = init+a.sum

func1func2 实现的功能是相同的,只是在参数列表的形式上有所不同。使用柯里化的形式可以使代码更加灵活,提高了函数的复用性和可读性。

函数作为参数传递的三种方式
val it = List(1, 2, 3, 4, 5, 6, 7)
def show(e:Int)=println(e)
it.foreach(show) 			// 【自定义】函数(重用) 		3
it.foreach(e=>println(e)) 	// 【自定义】函数(一次性)	   2
it.foreach(println) 		// 调用scala【已定义】函数	1

3、隐式参数,隐式函数

隐式函数作用:共用,简化
不建议使用太多,了解即可

场景一

// 当编译器在某个上下文中需要类型 Int 而实际提供的是类型 String 时,会查找适用的隐式转换函数并将字符串转换为整数。
implicit def str(a:String) = a.toIntval a: Int = "100"
val sum: Int = a + 1
println(sum)

场景二

def sum(array: Array[Int])(implicit a: Int = 0) = if (array.sum < 0) a else array.sumprintln(sum(Array(1, 2)))			// 3
println(sum(Array(1, 2, -4)))		// 0
println(sum(Array(1, 2, -4))(100))	// 100
def sum(array: Array[Int])(implicit a: Int) = if (array.sum < 0) a else array.sumimplicit val st: Int = 1000
println(sum(Array(1, 2, -4)))		// 1000

4、偏函数

只对输入的某些值定义的函数,而对其他值不进行定义。

// 定义一个偏函数,只处理偶数的情况
val evenNumber: PartialFunction[Int, String] = {case x if x % 2 == 0 => s"$x is even"
}// 使用偏函数处理输入值
println(evenNumber(2))  // 输出 "2 is even"
println(evenNumber(3))  // 抛出 MatchError 异常,因为偏函数未定义输入值为奇数的情况

5、总结

一、命名参数:
1、理解:默认入参规则是按方法或函数的参数列表顺序传参
2、应用:按 “参数名=值” 格式可以不遵循原始参数列表顺序传参

二、参数缺省值(默认值)
1、语法:声明方法时可以通过类似 (a:Int=5,…) 形式给参数提供【默认值】
2、应用:带有默认值的参数,若需要传入的就是默认值,则可缺省

三、匿名函数:将函数作为方法参数传递
1、语法:(参数列表)=>{方法体}

四、高阶函数
1、现象:将函数作为方法参数或返回类型
2、应用:函数作为返回类型:柯里化

五、中置表达式
1、语法:var v = 左元素 函数 右元素
2、案例:var range = 1 to|until 10
3、注意:方法的参数【只有一个参数】才可以使用中置表达式

六、嵌套函数
1、语法:允许在一个函数内部声明一个函数,作用域限当前函数内部

七、隐式参数
1、语法:参数前添加 implicit 关键字
2、限制:只能是最后一个参数列表且独占一个参数列表,自动传入同类型隐式值,通常和柯里化配合使用

八、隐式函数
1、语法:声明函数时,在 def 前添加 implicit 关键字
2、使用:类型转换,类型增强

implicit def toInt(str:String)=str.toInt
val b:Int = "123"	// 隐式转换implicit def bool(bool:Boolean) = if(bool) 1 else 0
val a:Int = false

九、闭包
1、概念:在函数内使用函数外定义的自由变量,则该函数即闭包
2、例如:

var a = 5
val add = (b:Int) => a+b

3、闭包能够捕获自由变量的变化,闭包对自由变量做出的改变闭包外亦可见(惰性处理:即函数执行后产生作用)

6、补充:下划线 _ 用途。

可以用于表示各种不同的语法元素,具体取决于上下文

通配符:在模式匹配、参数列表、导入语句等中,下划线 _ 可以用作通配符,表示匹配任意值或任意参数。

val list = List(1, 2, 3)
list.foreach(_ => println("Hello")) // 使用下划线作为参数,表示忽略参数

占位符:在部分应用函数、匿名函数等场景中,下划线 _ 可以作为占位符,表示一个参数的位置,类似于匿名函数中的参数。

val addOne: Int => Int = _ + 1	// 使用下划线作为参数占位符,表示参数
import package._				// 导全部包
case _							// default

部分应用函数:在柯里化函数中,下划线 _ 可以用作占位符,表示对某个参数进行部分应用,生成一个新的函数。

def add(a: Int)(b: Int): Int = a + bscala
val addTwo: Int => Int = add(2)(_) // 使用下划线作为部分应用函数的占位符// 基于下划线的简易传参语法:参数占位符,参数列表中每个参数可以使用一条下划线
def cal(func:(Int,Int)=>Int, a:Int*)={var sum = 0for (elem <- a) {sum = func(sum, elem)}sum
}
// 下面两种写法的效果相同
val rst = cal(_ + _, 1, 2, 3, 4, 5)
val rst = cal((a,b)=>a+b, 1, 2, 3, 4, 5)

占位符语法糖:在某些情况下,下划线 _ 可以用作语法糖,简化代码书写。

val list = List(1, 2, 3)
val sum = list.reduce(_ + _) // 使用下划线作为占位符,简化参数的书写

七、数组方法(重点)

1、创建数组

import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer(2, 3, 4, 5)
val length = buffer.length      //获取长度。
val bool0 = buffer.isEmpty      //是否为空。
val bool1 = buffer.nonEmpty     //是否不为空。
val bool2 = buffer.forall(x => x > 3)    //是否所有元素都满足给定的条件。
val bool3 = buffer.exists(x => x < 3)    //是否存在满足给定条件的元素。
val bool4 = buffer.contains(3)           //是否包含指定的元素
val bool5 = buffer.containsSlice(Seq(1, 2, 3)) // 是否包含指定的子序列
val bool6 = buffer.startsWith(Seq(1, 2))       //是否以指定的子序列开头
val bool7 = buffer.endsWith(Seq(4, 5))   //是否以指定的子序列结尾// 检查两个数组缓冲区是否具有相关性,即它们的对应位置的元素是否满足指定的关系。
val bool8 = buffer.corresponds(Seq(1, 2, 3))((a, b) => a == b * b)
// 检查两个数组缓冲区是否具有相同的元素,且元素在相同的位置上具有相同的值。
val bool9 = buffer.sameElements(Seq(1, 2, 3))
// 返回一个逆向的数组缓冲区
val reverse: ArrayBuffer[Int] = buffer.reverse

备注:

  • Seq 是一个 trait(特质),用于表示序列(Sequence)。序列是一个有序的集合,可以包含重复的元素。Seq 特质定义了一些常见的序列操作,例如获取元素、迭代、转换等。
  • Seq 特质有许多具体的实现类,其中一些常见的包括 ListVectorArrayBuffer 等。这些实现类提供了不同的性能和特性,以满足不同的使用场景。

2、基本操作

import scala.collection.mutable.ArrayBufferval buffer = ArrayBuffer(2, 3, 4, 5)
val length = buffer.length      //获取长度。
val bool0 = buffer.isEmpty      //是否为空。
val bool1 = buffer.nonEmpty     //是否不为空。
val bool2 = buffer.forall(x => x > 3)    //是否所有元素都满足给定的条件。
val bool3 = buffer.exists(x => x < 3)    //是否存在满足给定条件的元素。
val bool4 = buffer.contains(3)           //是否包含指定的元素
val bool5 = buffer.containsSlice(Seq(1, 2, 3)) // 是否包含指定的子序列
val bool6 = buffer.startsWith(Seq(1, 2))       //是否以指定的子序列开头
val bool7 = buffer.endsWith(Seq(4, 5))   //是否以指定的子序列结尾// 检查两个数组缓冲区是否具有相关性,即它们的对应位置的元素是否满足指定的关系。
val bool8 = buffer.corresponds(Seq(1, 2, 3))((a, b) => a == b * b)
// 检查两个数组缓冲区是否具有相同的元素,且元素在相同的位置上具有相同的值。
val bool9 = buffer.sameElements(Seq(1, 2, 3))
// 返回一个逆向的数组缓冲区
val reverse: ArrayBuffer[Int] = buffer.reverse

3、查找,定位

import scala.collection.mutable.ArrayBufferval buffer = ArrayBuffer(2, 3, 4, 5, 4)
val index1 = buffer.indexOf(3)                      // 查找第一次出现的位置
val index2 = buffer.indexOfSlice(Seq(2, 3, 4))      // 查找	子序列第一次出现的位置
val index3 = buffer.indexWhere(x => x % 2 == 0)     //查找第一个满足条件的元素的位置。
val index4 = buffer.lastIndexOf(3)                  //查找最后一次出现的位置
val index5 = buffer.lastIndexOfSlice(Seq(2, 3, 4))  //查找最后一次出现的位置。
val index6 = buffer.lastIndexWhere(x => x % 2 == 0) //查找最后一个满足条件的元素的位置

4、数据拷贝,移植

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer(2, 3, 4, 5, 4)
val items = buffer.clone()    // 创建并返回当前数组缓冲区的一个副本//将当前数组缓冲区的所有元素复制到指定的可变缓冲区 buf 中。
val buf: mutable.Buffer[Int] = mutable.Buffer(1, 34)
val buf2: mutable.ArrayBuffer[Int] = ArrayBuffer(3, 4)
buffer.copyToBuffer(buf2)
buf2.foreach(println)//将当前数组缓冲区的元素复制到指定的数组 array 中的指定位置,从索引 start 开始,复制长度为 len。
val array: Array[Int] = new Array(buffer.length)
buffer.copyToArray(array, start = 0, len = buffer.length)

5、添加

import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer((2, 3), (4, 5), (1, 4))
buffer.append((1, 111), (2, 3))       // 将一个或多个元素追加到末尾
buffer.appendAll(Array((3, 113)))     //将一个集合中的所有元素追加到末尾buffer.prepend((2, 112))              //将一个或多个元素插入到开头
buffer.prependAll(Array((4, 114)))    //将一个集合中的所有元素插入到开头buffer.insert(2, (5, 115), (34, 3))   //在指定位置插入一个或多个元素
buffer.insertAll(3, Array((6, 116)))  //在指定位置插入一个集合中的所有元素//++= 操作符可以将另一个集合的所有元素追加到当前数组缓冲区的末尾。
val combine: ArrayBuffer[(Int, Int)] = buffer ++= Seq((7, 117), (8, 118))
//:+ 操作符可以将一个元素追加到数组缓冲区的末尾,生成一个新的数组缓冲区。
val newBuffer1: ArrayBuffer[(Int, Int)] = buffer :+ (9, 119) :+ (1, 3)
//+: 操作符可以将一个元素添加到数组缓冲区的开头,生成一个新的数组缓冲区。
val newBuffer2: ArrayBuffer[(Int, Int)] = (10, 120) +: buffer

备注:

  • ++=:++:最终类型由左侧表达式的类型决定

6、删除

import scala.collection.mutable.ArrayBufferval buffer = ArrayBuffer(1, 3, 4, 4, 6, 19, 34, 22, 14, 23)//删除指定的单个元素,返回一个新的数组缓冲区。
val left1: ArrayBuffer[Int] = buffer - 3//删除指定集合中的所有元素,返回一个新的数组缓冲区。
val left2: ArrayBuffer[Int] = buffer -- Seq(1, 4)buffer -= 1             //删除指定的单个元素。
buffer --= Seq(3, 5)    //从数组缓冲区中删除指定集合中的所有元素val removedElement: Int = buffer.remove(1)  //删除指定位置上的元素,并返回被删除的元素
buffer.remove(1, 5)       //从指定位置开始删除指定数量的元素
buffer.clear()            //清空val left3: ArrayBuffer[Int] = buffer.drop(3)       //删除前 size 个元素,并返回剩余的元素。
val left4: ArrayBuffer[Int] = buffer.dropRight(2)  //删除后 size 个元素,并返回剩余的元素
val left5: ArrayBuffer[Int] = buffer.dropWhile(x => x < 6) //从左侧开始删除满足条件的元素,直到遇到第一个不满足条件的元素,并返回剩余的元素buffer.trimEnd(1)         //从数组缓冲区的末尾删除指定数量的元素
buffer.trimStart(1)       //从数组缓冲区的开头删除指定数量的元素
buffer.reduceToSize(3)    //削减数组缓冲区的容量,使其大小等于指定的大小。val distinct: ArrayBuffer[Int] = buffer.distinct //去重

7、修改

import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer(1, 3, 4, 4, 6, 19, 34, 22, 14, 23)
buffer.update(2, 555)     //修改指定下标的元素为新的元素
buffer.foreach(e => print(s"$e "))//返回一个新的数组缓冲区,其中指定下标的元素被替换为新的元素。
val newBuffer: ArrayBuffer[Int] = buffer.updated(1, 222)//  val after: ArrayBuffer[Int] = buffer.patch(from, seq, replaced)
// 从 from 开始,用指定的序列 seq 替换或插入元素,返回修改后的新数组缓冲区。
// 参数 replaced 控制替换或插入的行为:当 replaced = 0 时,表示插入;当 replaced > 0 时,表示替换;
// 如果 seq 为空且 replaced > 0,表示删除。
val after: ArrayBuffer[Int] = buffer.patch(0, Seq(2, 4), 0)

8、提取

val buffer = ArrayBuffer((1, 3), (4, 4), (6, 19), (34, 22), (14, 23))
val item1: (Int, Int) = buffer.apply(1)   //返回数组缓冲区中指定下标的元素。// 定义默认函数,当索引超出范围时返回默认值
def defaultFunction(index: Int): (Int, Int) = (0, 0)
// 返回数组缓冲区中指定下标的元素,如果索引超出范围,则返回由函数 defaultFunction 计算的默认值。
val item2: (Int, Int) = buffer.applyOrElse(1, defaultFunction)// 定义一个判断函数
def predicateFunction(element: (Int, Int)): Boolean = element._1 % 2 != 0
//返回数组缓冲区中满足条件的第一个元素的 Option 类型,如果没有满足条件的元素,则返回 None。
val opt: Option[(Int, Int)] = buffer.find(predicateFunction)
//返回一个新的数组缓冲区,其中包含数组缓冲区中满足条件的所有元素。
val remain1: ArrayBuffer[(Int, Int)] = buffer.filter(predicateFunction)
//返回一个新的数组缓冲区,其中包含数组缓冲区中不满足条件的所有元素。
val remain2: ArrayBuffer[(Int, Int)] = buffer.filterNot(predicateFunction)// 定义偏函数,用于将元组的第一个元素乘以 2,且第二个元素大于 10 的元组保留下来
val partialFunction: PartialFunction[(Int, Int), (Int, Int)] = {case (x, y) if y > 10 => (x * 2, y)
}
// 使用偏函数 pf 对数组缓冲区中的元素进行映射和过滤,返回一个新的数组缓冲区。
val items: ArrayBuffer[(Int, Int)] = buffer.collect(partialFunction)
// 使用偏函数 pf 对数组缓冲区中的第一个符合条件的元素进行映射,返回一个 Option 类型,如果找到符合条件的元素,则返回 Some(result),否则返回 None。
val firstItem: Option[(Int, Int)] = buffer.collectFirst(partialFunction)

下接:Scala 第二篇 算子篇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/826144.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL高级(索引-性能分析-explain执行计划)

explain 或者 desc 命令获取 MySQL 如何执行 select 语句的信息&#xff0c;包括在 select 语句执行过程中表如何连接和连接的顺序。 -- 直接在 select 语句之前加上关键字 explain / desc explain select 字段列表 from 表名 where 条件 &#xff1b; explain select * …

电机控制专题(一)——最大转矩电流比MTPA控制

文章目录 电机控制专题(一)——最大转矩电流比MTPA控制前言理论推导仿真验证轻载1Nm重载30Nm 总结 电机控制专题(一)——最大转矩电流比MTPA控制 前言 MTPA全称为Max Torque Per Ampere&#xff0c;从字面意思就可以知道MTPA算法的目的是一个寻优最值问题&#xff0c;可以从以…

SQL Server 2022 安装及使用

SQL Server 2022 前言一、安装SQL Server 2022下载SQL Server 2022安装SQL Server 2022配置SQL Server 2022 二、安装SQL Server Management Studio下载SQL Server Management Studio安装SSMS-Setup-CHS 三、使用SQL Server 2022四、解决连接到服务器报错问题 前言 SQL Serve…

git 快问快答

我在实习的时候&#xff0c;是用本地开发&#xff0c;然后 push 到 GitHub 上&#xff0c;之后再从 Linux 服务器上拉 GitHub 代码&#xff0c;然后就可以了。一般程序是在 Linux 服务器上执行的&#xff0c;我当时使用过用 Linux 提供的命令来进行简单的性能排查。 在面试的时…

应用编程之进程(三-通信篇)

所谓进程间通信指的是系统中两个进程之间的通信&#xff0c;不同的进程都在各自的地址空间中、相互独立、隔离&#xff0c;所以它们是处在于不同的地址空间中&#xff0c;因此相互通信比较难&#xff0c;Linux 内核提供了多种进程间通信的机制。 大部分的程序是不要考虑进程间…

Microchip逆市扩张,接连收购2家公司

尽管年初传来降薪停工的消息&#xff0c;全球领先的半导体解决方案供应商Microchip并未因此停下扩张的脚步。相反&#xff0c;该公司在短短的一个月内&#xff0c;接连宣布收购两家公司&#xff0c;展现了其坚定的市场布局和前瞻的战略眼光。 4月11日&#xff0c;Microchip成功…

二进制OpenStack

二进制搭建OpenStack 1.环境准备 1.1机器的准备 主机名服务器配置操作系统IP地址controller-node4C8Gcentos7.9172.17.1.117computer-node4C8Gcentos7.9172.17.1.118 1.2网络架构 [rootcotroller-node ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noque…

Java JNI调用本地方法1(调用C++方法)

一、基础概念 1、JNI&#xff08;Java Native interface&#xff09;:sun公司提供的JNI是Java平台的一个功能强大的接口&#xff0c;实现java和操作系统本地代码的相互调用功能&#xff0c;系统本地代码通常是由其他语言编写的&#xff0c;如C。 二、JNI使用步骤 1、定义一个J…

选定进行压缩的卷可能已损坏。请使用chkdsk来修复损坏问题,然后尝试再次压缩该卷

Windows Server 2008R2环境下&#xff0c;进行磁盘重新分区时&#xff0c;想要对系统盘进行“压缩卷”&#xff0c;结果报错提示“选定进行压缩的卷可能已损坏。请使用Chkdsk来修复损坏问题&#xff0c;然后尝试再次压缩该卷。”这是硬盘出现了坏道导致的&#xff0c;硬盘出错无…

中仕公考:教师编制和事业单位d类一样吗?

教师编制和事业单位D类在考试内容、专业要求、晋升途径等方面有很大的不同中仕为大家介绍一下&#xff1a; 考试内容&#xff1a;教师编的考试包括教育综合知识和学科专业知识&#xff0c;有的地区会额外考公共基础知识。事业单位D类的考试更侧重于职业能力倾向测验和综合应用…

Linux的学习之路:14、文件(1)

摘要 有一说一文件一天学不完&#xff0c;细节太多了&#xff0c;所以这里也没更新完&#xff0c;这里部分文件知识&#xff0c;然后C语言和os两种的文件操作 目录 摘要 一、文件预备 二、c文件操作 三、OS文件操作 1、系统文件I/O 2、接口介绍 四、思维导图 一、文件…

uniapp全局监听分享朋友圈或朋友

把大象装进冰箱需要几步&#xff1a; 1、创建shart.js文件 export default{data(){return {//设置默认的分享参数//如果页面不设置share&#xff0c;就触发这个默认的分享share:{title:标题,path:/pages/index/index,imageUrl:图片,desc:描述,content:内容}}},onLoad(){let ro…

若依前后端部署到一起

引用&#xff1a;https://blog.csdn.net/qq_42341853/article/details/129127553 前端改造&#xff1a; 配置打包前缀 修改router.js 编程hash模式&#xff1a; 前端打包&#xff1a;npm run build:prod 后端修改&#xff1a; 添加thymeleaf包&#xff0c;和配置文件 spri…

JAVA 项目<果园之窗>_1

这几天有空看能不能把水果店管理系统整出来&#xff0c;目标是整个网页版本的&#xff0c;以我的电脑做服务器&#xff0c;数据存在mysql中 以我目前的理解整个项目大致可分为前端部分、后端部分、数据库部分&#xff0c;也就这三个部分 目前打开并运行了一个别人的项目&#…

leetcode(474.最大连续1的个数)(python)

看数据范围知&#xff0c;复杂度不超过&#xff08;nlogn&#xff09;&#xff0c;不过感觉LeetCode很少卡算法时间。 题目要求数组的*****的个数&#xff0c;想到dp动态规划 dp[i][0]表示前i个数字&#xff0c;以第i个元素结尾&#xff0c;全为1的个数 dp[i][1]表示前i个数…

React间接实现一个动态组件逻辑

在开发一个浏览器插件的时候&#xff0c;用的plasmo框架和react支持的&#xff0c;里面使用react开发一个菜单功能&#xff0c;但是又不想使用react-router&#xff0c;所以就想着能不能使用一个很简单的方式做一个替代方案&#xff1f;那肯定是可以。 我在引入一个组件后&…

vue2响应式 VS vue3响应式

Vue2响应式 存在问题&#xff1a; 新增属性&#xff0c;删除属性&#xff0c;界面不会更新。 直接通过下标修改数组界面不会自动更新。 Vue2使用object.defineProperty来劫持数据是否发生改变&#xff0c;如下&#xff1a; 能监测到获取和修改属性&#xff1a; 新增的属性…

C++笔记:类和对象(一)

类和对象 认识类和对象 先来回忆一下C语言中的类型和变量&#xff0c;类型就像是定义了数据的规则&#xff0c;而变量则是根据这些规则来实际存储数据的容器。类是我们自己定义的一种数据类型&#xff0c;而对象则是这种数据类型的一个具体实例。类就可以理解为类型&#xff0c…

line 1:20 no viable alternative at input ‘point,‘

背景 遇到一个蛋疼的问题&#xff0c;搞得老夫难受的一&#xff0c;解决了索性记录下 Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession61b0005f] was not registered for synchronization because synchronization is not activ…

python爬虫-----深入了解 requests 库(第二十五天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…