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 + b
    if(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 DatabaseData

  def 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)	//输出:email
    
    val 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.toInt

val 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.sum

println(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.sum
	
implicit 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 = 0
    for (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.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

3、查找,定位

import scala.collection.mutable.ArrayBuffer

val 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.ArrayBuffer

val 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.mfbz.cn/a/559275.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大语言模型+Lora微调】10条对话微调Qwen-7B-Chat并进行推理 (聊天助手)

代码&#xff1a;https://github.com/QwenLM/Qwen/tree/main 国内源安装说明&#xff1a;https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary 通义千问&#xff1a;https://tongyi.aliyun.com/qianwen 一、环境搭建 下载源码 git clone https://github.com/QwenLM/Qwen…

【python】如何通过python来发邮件,各种发邮件方式详细解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

27 管道

概念 管道式Unix中最古老的进程间通信的形式 把从一个进程连接到另一个进程的一个数据流称为一个“管道” 原理 task_struct中保存了一个files的结构体数组&#xff0c;里面存储了所有打开文件的编号&#xff0c;新打开一个文件&#xff0c;数据会写入到文件对应的 缓冲区中去…

程序,进程,进程管理的相关命令

程序 程序是执行特定任务的代码 1.是一组计算机能识别和执行的指令&#xff0c;运行于电子计算机上&#xff0c;满足人们某种需求的信息化工具 2.用于描述进程要完成的功能&#xff0c;是控制进程执行的指令集 进程的状态 为了对进程进行管理&#xff0c;操作系统首先定义…

上位机图像处理和嵌入式模块部署(树莓派4b实现xmlrpc通信)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面&#xff0c;我们也用纯API实现过上位机和开发板之间的通信。当时使用的方法&#xff0c;就是用windows自带的网络sdk和linux自带的api函数来完…

rc_visard 3D Stereo Senso

1 简介 rc_visard 3D立体视觉传感器 支持的接口标准 GenICam Generic Interface for CamerasGigE Gigabit Ethernet 词汇表 SGM semi-global matching 半全局匹配 SLAM Simultaneous Localization and Mapping 即时定位与地图构建 2 安全 3 硬件规格 坐标系 rc_visar…

linux信号相关概念

signal 信号引入什么是信号&#xff1f;如何产生信号&#xff1f;通过按键产生信号调用系统函数向进程发信号系统调用函数发送信号的流程: 由软件条件产生信号软件发送信号的流程&#xff1a; 硬件异常产生信号硬件异常的流程&#xff1a; Deliver、Pending、Block概念信号在内…

【Ne4j图数据库入门笔记1】图形数据建模初识

1.1 图形建模指南 图形数据建模是用户将任意域描述为节点的连接图以及与属性和标签关系的过程。Neo4j 图数据模型旨在以 Cypher 查询的形式回答问题&#xff0c;并通过组织图数据库的数据结构来解决业务和技术问题。 1.1.1 图形数据模型介绍 图形数据模型通常被称为对白板友…

明文scheme拉起此小程序

微信开发文档说明&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-scheme.html 1、开发者无需调用平台接口&#xff0c;在MP平台->设置->隐私与安全->明文Scheme拉起此小程序声明后&#xff0c;可自行根据如下格式拼接app…

【静态分析】软件分析课程实验A1-活跃变量分析和迭代求解器

1 作业导览 为 Java 实现一个活跃变量分析&#xff08;Live Variable Analysis&#xff09;。实现一个通用的迭代求解器&#xff08;Iterative Solver&#xff09;&#xff0c;用于求解数据流分析问题&#xff0c;也就是本次作业中的活跃变量分析。 Live Variable Analysis 详…

facenet人脸检测+人脸识别+性别识别+表情识别+年龄识别的C++部署

文章目录 一. 人脸检测二.人脸识别facenet2.1 训练人脸识别模型2.2 导出ONNX2.3 测试 三.人脸属性&#xff08;性别、年龄、表情、是否戴口罩&#xff09;3.1 训练3.2 导出ONNX3.3 测试 四. 集成应用五、Jetson 部署5.1 NX5.2 NANO 一. 人脸检测 代码位置&#xff1a;1.detect …

深入理解数据结构第五弹——排序(2)——快速排序

排序&#xff08;1&#xff09;&#xff1a;深入了解数据结构第四弹——排序&#xff08;1&#xff09;——插入排序和希尔排序-CSDN博客 前言&#xff1a; 在前面我们已经讲过了几种排序方式&#xff0c;他们的效率有快有慢&#xff0c;今天我们来学习一种非常高效的排序方式…

【windows-搭建Ubuntu22LTS】

一、环境要求 1. windows版本要求 至少Windows 10 2020年5月(2004) 版, Windows 10 2019年5月(1903) 版&#xff0c;或者 Windows 10 2019年11月(1909) 版 2. 控制面板开启相关的程序(需要重启) 二、Microsoft store安装unbuntu 下载后直接运行&#xff08;稍微等会&#…

Linux软件安装和部署Java代码

文章目录 1.软件安装1.1.软件安装方式1.2.常用软件安装1.2.1 安装jdk1.2.2 安装Tomcat1.2.3 安装MySQL1.2.4 安装lrzsz 2.项目部署2.1.手工部署项目2.2 通过Shell脚本自动部署项目 1.软件安装 1.1.软件安装方式 &#xff08;1&#xff09;二进制发布包安装&#xff1a; 软件已…

基于SSM的学校在线考试系统的设计与实现

功能需求 管理员模块 管理员模块是整个学校在线考试系统中最为重要的管理者&#xff0c;能够对网站内的各种信息进行管理&#xff0c;能够对教师、学生的个人资料进行管理&#xff0c;对于已经离校的学生将其剔除考试名单&#xff0c;将新入校的学生纳入到考试名单中。对于入…

用 element ui 实现季度选择器

由于在数据项目中经常以各种时间条件查询数据&#xff0c;所以时间选择器&#xff08;DatePicker&#xff09;组件是很常用的组件。但是在我使用的 Element UI 中&#xff0c;缺少了季度选择器的功能。 简易实现 一开始我根据时间范围使用 select 去遍历,如 2024-Q1、2023-Q4…

win/mac达芬奇19下载:DaVinci Resolve Studio 19

DaVinci Resolve Studio 19 是一款功能强大的视频编辑和调色软件&#xff0c;广泛应用于电影、电视和网络节目的后期制作。这款软件不仅提供了专业的剪辑、调色和音频处理工具&#xff0c;还引入了全新的DaVinci Neural Engine AI工具&#xff0c;对100多项功能进行了大规模升级…

美化博客文章(持续更新)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;游戏实现&#xff1a;贪吃蛇​​​​​​ &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 该文提供我的一些文章设计的一些方法 目录 1.应用超链接 1.应用超链接

差速机器人模型LQR 控制仿真——路径模拟

LQR路径跟踪要求路径中带角度&#xff0c;即坐标&#xff08;x,y,yaw&#xff09;&#xff0c;而一般我们的规划出来的路径不带角度。这里通过总结相关方法&#xff0c;并提供一个案例。 将点路径拟合成一条完整的线路径算法 将点路径拟合成一条完整的线路径是一个常见的问题…

【Java开发指南 | 第十五篇】Java Character 类、String 类

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 Java Character 类转义序列 Java String 类连接字符串 Java Character 类 Character 类是 Java 中用来表示字符的包装类&#xff0c;它提供了一系列静态方法用于对字符进行操作&#xff0c;其主要分为静态方法…
最新文章