工作如何繁忙,生活如何糟心,至少求知的这一刻是我的…
前言
基于Scala 2.12.14。学的《Scala for the Impatient》,记录每天的笔记,有些名词看的英文,翻得未必准确。
适用对象:Java程序员。尽可能在短时间内建立起Java到Scala的转换,做到能看能写。实际上在学习一门语言,应当逐步抛弃掉固有成见,才能发现其中乐趣。人生苦短,别用Java:(逃。
今日重点
- 定长数组
- 不定长数组
- 多维数组
- 操作数组的方式
定长数组
// 长度为10的整数数组,初始化值为0
val foo = new Array[Int](10)
// 自定义初始化值,使用apply特性
val bar = Array(1, 2, 3)
// 同样赋值也可以用到apply特性
bar(0) = 4
在JVM中,Scala的定长数组的实现和Java是一致的。
不定长数组
Scala中不定长数组是ArrayBuffer,从功能上等同Java中的ArryayList。
import scala.collection.mutable.ArrayBuffer
// 等价于 val ab = new ArrayBuffer[Int]
val ab = ArrayBuffer[Int]()
ab += 1
// [1]
ab += (2, 3)
// [1, 2, 3]
// 使用++=合并任何集合(collection)
ab ++= Array(4, 5)
// [1, 2, 3, 4, 5]
ab.trimEnd(1)
// [1, 2, 3, 4]
// 转换为定长数组
val arr = ab.toArray
多维数组
建立一个多维数组:
// 二维数组,三行四列
val matrix = Array.ofDim[Int](3, 4)
// 访问第二行第三列
matrix(1, 2)
ofDim方法只有Array有。
建立一个多维不规则数组(忘了专有名词,只记得大学学过hhh,ragged arrays):
val ragged = new Array[Array[Int]](2)
for (i <- ragged.indices)
ragged(i) = new Array[Int](i + 1)
数组操作
随机访问
ab.insert(2, 3)
// [1, 2, 3, 3, 4]
ab.insert(4, 5, 6]
// [1, 2, 3, 3, 4, 5, 6]
ab.remove(2)
// [1, 2, 3, 4, 5, 6]
ab.remove(4, 5)
// [1, 2, 3, 4]
遍历数组
在Scala中定长和不定长数组的遍历方式一致:
for (i <- ab) {
println(i)
// 复习一下插值器
println(s"${i}")
}
// 这种循环方式等价于
for (i <- ab.indices) {
// indices方法生成一个索引集合,可以对它执行reverse,就实现逆向循环了
println(ab(i))
}
// 还等价于
for (i <- 0 until ab.length) {
println(ab(i))
}
// 设定步长为2
for (i <- 0 until ab.length by 2) {
println(ab(i))
}
处理数组
// 生成新的数组
// for/yield循环会创建与原集合相同类型的集合
val newAb = for (ele <- ab) yield 2 * ele
处理满足特定条件的元素:
val conditionAb = for (ele <- ab if ele / 2 == 0) yield 2 * ele
别忘了Scala是函数式编程的一门语言,那么也有对应的函数式编程的写法:
ab.filter(_ / 2 == 0).map(2 * _)
高效处理
假设我们需要去除一个集合中的特定元素,那么最直观的方法自然是遍历集合并判断是否删除该元素:
// 删除数组中的负数
var n = ab.length
var i = 0
while (i < n) {
if (0 <= ab(i)) i += 1
else { ab.remove(i); n -= 1 }
}
这种方式需要记录当前遍历数组的索引,以及每次删除都要移动中间元素。如果能一次性将要删除的元素标记出来,再挨个反向删除,能减少删除元素带来的移动元素:
// 记录要删除的元素索引,并一次性删除
val readyToRemove = for (i <- ab.indices if ab(i) < 0) yield i
for (i <- readyToRemove.reverse) ab.remove(i)
还有一种方法是记录下需要保留的元素到数组头部,接着裁剪数组:
val readyToCopy = for (i <- ab.indices if 0 <= ab(i)) yield i
for (j <- readyToCopy.indices) ab(j) = ab(readyToCopy(j))
ab.trimEnd(ab.length - readyToCopy.length)
大学倒还有细致研究过这些技巧,现在工作时反而不在意这些细节,程序和我有一个能跑就行,hhh。
通用算法
Scala为集合提供了许多便捷的算法,在绝大多数场景下,它们一般是较优或最优的算法,没有非功能要求就直接使用:
val sum = ab.sum
val max =ab.max
val sorted = ab.sorted
// 按指定排序方法排序,示例降序
val desc = ab.sortWith(_ > _)
// 快排,只能作用在定长数组上
import scala.util.Sorting.quickSort
quickSort(Array(3, 10, 1))
Scala还提供了便捷的将数组转换为String的方式,便于我们输出:
ab.mkString
// res12: String = 123
ab.mkString(", ")
// res13: String = 1, 2, 3
// 试试这个
ab.mkString("<", ",", ">")
// 对变长和定长数组分别执行toString呢?
ab.toString
// res14: String = ArrayBuffer(1, 2, 3)
Array(1, 2, 3).toString
// res15: String = [I@1bf8b5d9