第4章数据结构(重点练习章节)
4.1主要的集合特质
4.1主要的集合特质
Scala同时支持可变集合和不可变集合,
不可变集合从不可变,可以安全的并发访问。
4.2数组
Scala优先采用不可变集合。
集合主要分为三大类:序列、集、映射
所有集合都扩展自Iterable特质。
对于几乎所有的集合类,Scqla都同时提供了可变和不可变的版本。
Seq是一个有先后次序的值得序列。
IndexedSeq能够通过整形下标快速访问元素。
Set是一个没有先后次序的值集合。
在SortedSort中,元素以某种排过序的顺序被访问。
Map是一组键值对偶,SortedMap按照键的排序访问其中的实体。
4.2.1定长数组
如果需要一个定长数组,可以使用Scala中的Array,Array 以java数组的方式实现。
4.2.2变长数组
变长数组可以使用ArrayBuffer,Java中有ArrayList
4.2.3数组转换
转换动作不会修改原数组,而是产生一个新的数组。
4.2.4多维数组
和Java一样,多维数组通过数组的数组来实现,可以用ofDim方法。
4.2.5和Java数组的互操作
Scala数组是通过Java进行实现的
使用scala.collection.convert.AsJavaConverters
或者AsScalaConverters进行转换
4.3映射
4.3.1映射操作
映射就是key-value的集合,就类似于Java中的Map。
不可变映射也可以调用方法,只不过产生新的映射。
新映射和老映射共享大部分结构。可变映射是在原映射基础上进行修改。
4.3.2和Java的互操作
使用JavaConversions进行转换
4.4元组
元组是不同类型的值的聚集
元组使用_1,_2,_3来访问
元组是从1开始不是0;
元组可用于函数需要返回不止一个值得情况
4.5队列
队列是一个先进先出的结构:
4.6堆栈
Stack是一个先进后出的结构
4.7列表
如果List为空,用Nil来表示。
4.8集
集是不重复元素的结合。集不保留顺序,默认是以哈希集实现。
4.9添加去除元素操作符
1.向后(:+)或向前(+:)追加元素到序列当中。
2.添加(+)元素到无先后次序的集合中。
3.用-移除元素。
4.用++和--来批量添加和移除元素。
5.对于列表,优先使用::和.
6.改值操作有+=、++=、-=和--=。
7.对于集合,我更喜欢++、--和--=。
8.我尽量不用++:、+:和++-:。
4.10常用方法
4.11将函数映射到集合
map应用于集合中的每一个元素,并产生转换后的一个新元素。
flatmap同样应用于集合的每一个元素,对于每一个元素产出一个集合,并将集合中的元素串接在一起。
4.12化简、折叠、扫描
将二元函数应用于集合中的元素
4.13拉链操作
作用于两个集合,将对应的元素合并成一个元组。
4.14迭代器
通过iterator方法从集合获得一个迭代器
4.15流(不可变列表)
流Stream只有在需要的时候才会去计算下一个元素
4.16懒视图
:: 返回一个流
view不会缓存数据,每次都要重新计算
4.17与java集合的互操作总结。
4.18线程安全的集合
Scala类库提供了6个并发特质,可以通过混入这些集合,让集合的操作变成同步的
4.19并行集合
Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
并行集合位于scala.collection.parallel,分immutable和mutable。
通过par关键字将集合转换为一个并行集合
通过ser方法将并行集合转换回串行集合。
注意:在并行任务里面,不要同时更新一个共享变量。
4.20操作符概述
1、如果想在变量名、类名等定义中用保留字,可以用反引号:val‘val'=42
2、这种形式叫中置操作符,A操作符B等同于A.操作符(B)
3、后置操作符,A操作符等同于,A.操作符,如果操作符定义的时候不带()则调用时不能加()
4、前置操作符,+、一、!、~等操作符A等同于A.unary_操作符
5、赋值操作符,A操作符=B等同于A=A操作符B
import java.awt.Font
import org.scalatest.FunSuite
class Chapter03CoreTest extends FunSuite {
test("core01") {
//定长数组
val s = Array("Hello", "World")
println(s.mkString(","))
s(1) = "scala"
//变长数组
import scala.collection.mutable.ArrayBuffer
var arrayBuffer = new ArrayBuffer[Int]()
//元素追加
arrayBuffer += 1
arrayBuffer += (2, 3, 4, 5)
arrayBuffer ++= Array(8, 13, 21)
println(arrayBuffer.mkString(","))
//元素移除
arrayBuffer.trimEnd(2)
//元素插入
arrayBuffer.insert(2, 6)
println(arrayBuffer.mkString(","))
//变长数组语定长数组之间的互转
val array1 = arrayBuffer.toArray
val buffer1 = s.toBuffer
//数组的遍历
for (i <- 0 to arrayBuffer.size - 1) println(arrayBuffer(i))
// 数组通过下标访问
for (i <- 0 until array1.length)
println(i + ": " + array1(i))
//产生一个Range序列
val range1 = 0 until(4, 1)
println(range1.reverse)
// a 遍历
for (elem <- array1)
println(elem)
// a 索引
for (i <- array1.indices)
println(i + ": " + array1(i))
}
test("core02") {
// 产生新的数组
val a = Array(2, 3, 4, 5)
val result = for (i <- a) yield 2 * i
//数组转字符串
println(result.mkString(","))
//数组排序
result.sorted
//快速排序
scala.util.Sorting.quickSort(result)
println(result.mkString(","))
println(result.toString)
//统计大于0的个数
println(result.count(_ > 0))
import scala.collection.mutable.ArrayBuffer
var buffer = ArrayBuffer(1, 2, 3)
//追加
buffer.append(1)
//追加数组
buffer.appendAll(ArrayBuffer(1, 2, 3))
val result2 = Array(1)
// result2.copyToArray(result)
//添加20项 使用-1填充
result2.padTo(20, -1)
}
test("core03") {
//多维数组 矩阵 3行四列
val matrix = Array.ofDim[Double](3, 4)
val row = 0
val column = 2
//赋值
matrix(0)(2) = 18.99
println(matrix.length)
println(matrix(row).length)
}
test("core04") {
// scala 和Java的相互操作
import scala.collection.JavaConversions._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls", "-al", "/")
// val pb = new ProcessBuilder(command.asJava)
// val cmd:mutable.Buffer[String] = pd.command().asScala
// assert(cmd == command)
}
test("core05") {
//不可变的map "Jim" -> 10称为对偶
val map1 = Map("Jim" -> 10, "Bob" -> 3, "lucy" -> 8)
//可变的map
val map2 = scala.collection.mutable.Map("Jim" -> 10, "Bob" -> 3, "lucy" -> 8)
// 空映射
val scores = new scala.collection.mutable.HashMap[String, Int]
//对偶元组
val map3 = Map(("Alice1", 11), ("Alice2", 11), ("Alice3", 11))
//取值
println(map1.get("Jim"))
println(map1.getOrElse("Jim", "0"))
// contains检测
val fredsScore = if (scores.contains("Fred")) scores("Fred") else 0
//设置参数值
map1("Jim") = 100
// map1("Bob")=11
//遍历map
for ((k, v) <- map1) println(k + "is mapped to" + v)
//keyset集合
val set = map1.keySet
//遍历所有的value
for (v <- map1.values) println(v)
//产生新的Map
for ((k, v) <- map1) yield (v, k)
//排序的map
val map4 = scala.collection.immutable.SortedMap("Alice" -> 10, "Fred" -> 11)
//双向链表HashMap
val months = scala.collection.mutable.LinkedHashMap("Jan" -> 1)
}
test("core06") {
//map和Java的相互转换
import scala.collection.JavaConverters._
val ids = java.time.ZoneId.SHORT_IDS.asScala
val props = System.getProperties.asScala
import java.awt.font.TextAttribute._
val attrs = Map(FAMILY -> "Serif", SIZE -> 12)
val front = new Font(attrs.asJava)
}
test("core07") {
//元祖
val tuple = (1, 2, 3, "Fred")
//元祖访问
val second = tuple._2
//元祖访问
val first = tuple._1
//拉链操作
val symbols = Array("<", "-", ">")
val counts = Array(2, 10, 2)
//zip 拉链操作
val pairs = symbols.zip(counts)
//遍历
for ((s, n) <- pairs) println(s * n)
//拉链操作 转Map
symbols.zip(counts).toMap
}
test("core08") {
import scala.collection.mutable
//声明一个队列
val q1 = new mutable.Queue[Int]()
//队列追加元素
q1 += 2
q1 += 1
//追加多个元素并返回队列
q1 ++= List(2, 3)
//返回并从队列删除第一个元素
q1.dequeue()
//追加多个元素 返回Unit
q1.enqueue(5, 3, 6)
//头
print(q1.head)
//尾
print(q1.tail)
}
test("core09") {
import scala.collection.mutable
//声明一个栈
val s = new mutable.Stack[Int]()
//入栈
s.push(1)
s.push(1, 2)
//出栈
s.pop()
s.push(3)
//获取栈顶元素
s.top
}
test("core10") {
//列表
val digists = List(4, 2)
//右边结合操作符
9 :: List(4, 2)
//NIL表示空列表
9 :: 4 :: 2 :: Nil
// 9 :: (4 :: (2 :: Nil))
sum(List(1, 2, 3))
sum2(List(1, 2, 3))
//sum求和
List(1, 2, 3).sum
}
def sum(lst: List[Int]): Int = if (lst == Nil) 0 else lst.head + sum(lst.tail)
def sum2(lst: List[Int]): Int = lst match {
case Nil => 0
case h :: t => h + sum(t)
}
test("core11") {
//set不可重复集合
var numberSet = Set(1, 2, 3)
//set 追加元素
numberSet += 5
//set 大小
println(numberSet.size)
//set 减去元素
Set(1, 2, 3) - 3
//set 追加元素
Set(1, 2, 3) + 1
//遍历 set
for (x <- Set(1, 2, 3)) println(x)
}
test("core12") {
//map映射
val names = List("Peter", "Paul", "Mary")
//map
names.map(_.toLowerCase) // List("PETER", "PAUL", "MARY")
//等价于map操作
for (n <- names) yield n.toUpperCase()
//flatMap操作 打平
}
// def ulcase(s: String) = Vector(s.toLowerCase(), s.toUpperCase)
test("core13") {
//部分简化操作
List(1, 2, 3).reduceLeft(_ - _)
List(1, 2, 3).reduceRight(_ - _)
//折叠操作
List(1, 2, 3, 4).foldLeft(0)(_ - _)
val freq = scala.collection.mutable.Map[Char, Int]()
for (c <- "Miss") freq(c) = freq.getOrElse(c, 0) + 1
//扫描操作
(1 to 10).scanLeft(0)(_ + _)
}
test("core14") {
val prices = List(1, 2, 3)
val quantites = List(1, 2, 3)
prices zip quantites
//拉链后执行map操作
(prices zip quantites) map { p => p._1 * p._2 }
List(1, 2, 3) zip List(1, 2, 3)
List(1, 2, 3).zipAll(List(10, 2), 0, 2)
"Scala".zipWithIndex
"Scala".zipWithIndex.max
"Scala".zipWithIndex.max._2
//unzip函数可以将一个元素的列表转换成一个列表的元祖
"scala".zipWithIndex.unzip
"scala".zipWithIndex.unzip._1
"scala".zipWithIndex.unzip._2
}
test("core15") {
//切片操作返回一个迭代器
val iterator = (1 to 10).sliding(3)
while (iterator.hasNext) println(iterator.next())
val iterable2 = (1 to 10).sliding(3)
//遍历长度
for (i <- iterable2) print(i)
//获取长度
println(iterable2.length)
//iterable2 会移动指针
println(iterable2.hasNext)
//返回迭代器数组
println(iterable2.toArray)
}
// #::返回一个流
def numsForm(n: BigInt): Stream[BigInt] = n #:: numsForm(n + 1)
test("core16") {
val tenOrMore = numsForm(10)
//尾部
tenOrMore.tail
//头部
tenOrMore.head
//最后一个元素
tenOrMore.tail.tail.tail
//对流执行求值运算
val squares = numsForm(5).map(x => x * x)
squares.take(5).force
}
def sq(x: Int): Stream[Int] = {
println(x)
x * x
} #:: sq(x + 1)
test("core17") {
//view的懒执行 不是很好理解
//view不会缓存数据,每次都要重新计算
// import scala.math._
val p = (1 to 10).view.map(x => {
println(x)
x * x
})
p.take(10).mkString(",")
val p1 = sq(0)
p1(10)
p1.take(10).last
}
test("core18") {
//通过par关键字将集合转换为一个并行集合
(1 to 5).par.foreach {
it => println(Thread.currentThread().getName()); print("^" + it)
}
val c = (1 to 5).map(_ + 100)
println(c)
}
}