第4章 数据结构

4.1 主要的集合特质

Scala 同时支持可变集合和不可变集合,不可变集合从不可变,可以安全
的并发访问。
两个主要的包:
1) 不可变集合:scala.collection.mutable
2) 可变集合: scala.collection.immutable
Scala 优先采用不可变集合。集合主要分为三大类:序列(list)、集(set)、映射(map)。
所有集合都扩展自 Iterable 特质。对于几乎所有的集合类,Scala 都同时
提供了可变和不可变的版本。

Seq 是一个有先后次序的值得序列。IndexedSeq 能够通过整形下标快速
访问元素。
Set 是一个没有先后次序的值集合。在 SortedSort 中,元素以某种排过序
的顺序被访问。
Map 是一组键值对偶,SortedMap 按照键的排序访问其中的实体。
每个 Scala 集合特质或者类都有一个带有 Apply 方法的伴生对象(类似
于静态方法),这个 apply 方法可以用来构建该集合中的实体。

这样的设计叫“统一创建原则”。

4.2 数组 Array

定长数组

如果需要一个定长数组,可以使用 Scala 中的 Array,Array 以 java 数组
的方式实现。
    //1.定长数组val arr1 = new Array[Int](10) //不定义[Int] 默认为 [Nothing]println(arr1.mkString(","))val arr2 = Array(1, 2, 3)println(arr2.mkString(","))arr2.apply(1)//赋值arr2(1) = 10 //等价于 arr2.update(1, 10)println(arr2.mkString(","))//追加val arr3 = arr1 :+ "??"val arr4 = "??" :+ arr1println(arr3.mkString(", "))

变长数组

变长数组可以使用 ArrayBuffer,Java 中有 ArrayList,
    //2.变长数组//小括号可以存放初始化的元素内容val arrBuffer1 = ArrayBuffer[Int](10, 9, 8)val arrBuffer2 = ArrayBuffer[Int]() //小括号中指定的元素println(arrBuffer1) //ArrayBuffer(10, 9, 8) 直接打印的是数组println(arrBuffer2) //ArrayBuffer()println(arrBuffer1.mkString(",")) //10,9,8//赋值,取值arrBuffer1(1) = -1println(arrBuffer1) //ArrayBuffer(10, -1, 8)println(arrBuffer1(1)) //-1println(arrBuffer1.apply(2)) //8//追加arrBuffer1.append(1, 2, 3)println(arrBuffer1) //ArrayBuffer(10, -1, 8, 1, 2, 3)
val arrBuffer3 = arrBuffer1 :+ 90println(arrBuffer1) //ArrayBuffer(10, -1, 8, 1, 2, 3)println(arrBuffer3) //ArrayBuffer(10, -1, 8, 1, 2, 3, 90)

数组遍历:
for (i <- 0 until a.length)println(i + ": " + a(i))for (elem <- a)println(elem)

数组转换

转换动作不会修改原数组,而是产生一个新的数组。
Array 与 ArrayBuffer 的互转:
ArrayBuffer = Array.toBuffer
Array = ArrayBuffer.toArray

多维数组

和 Java 一样,多维数组通过数组的数组来实现,可以用 ofDim 方法。 
val matrix = Array.ofDim[Double](3, 4)赋值:
matrix(row)(column) = 17.29

和 Java 数组的互操作

Scala 数组是通过 Java 进行实现的,所以可以进行互相转换操作,使用
scala.collection.convert. AsJavaConverters 或者 AsScalaConverters 进行转换 、
import scala.collection.JavaConverters._
import scala.collection.mutable.ArrayBufferval command = ArrayBuffer("ls", "-al", "/")
val pb = new ProcessBuilder(command.asJava) // Scala to Java

val cmd : Buffer[String] = pb.command().asScala // Java to Scala

cmd == command

4.3 元组 Tuple

//元组//创建val tuple1 = (1, 2, 3, "hello", 4)//赋值 取值
    println(tuple1._4)//tuple 的遍历//方式一:for(e <- tuple1.productIterator){println(e)}//方式二
    tuple1.productIterator.foreach(println(_))tuple1.productIterator.foreach(i => println("tuplel中的元素:" + i))

4.4 列表 List

    //列表 Listval list1 = List(1, 2)//取值 赋值println(list1(1))val list1_2 = list1.updated(1, 10)println(list1) //List(1, 2) //list 集合不能在原有基础上修改值println(list1_2) //List(1, 10)//追加,另一种创建方式val list2 = 1 :: 2 :: 3 :: Nil //Nil 表示空的listval list3 = 1 :: 2 :: 3 :: List(6, 7) //Nil 表示空的listval list4 = 1 :: 2 :: 3 :: List(6, 7) :: Nilprintln(list2) //List(1, 2, 3)println(list3) //List(1, 2, 3, 6, 7)println(list4) //List(1, 2, 3, List(6, 7))println(Nil) //List()//ListBufferval list5 = ListBuffer[Int]()list5.append(1, 2)println(list5) //ListBuffer(1, 2)
list5 update(0, 10) //ListBuffer 可以在原有基础上修改值println(list5) //ListBuffer(10, 2)

4.5 队列 Queue

   //队列val q1 = mutable.Queue[Int](1, 2)println(q1) //Queue(1, 2)val q2 = new mutable.Queue[Int]()q2 ++= q1println(q2) //Queue(1, 2)//取值 赋值println(q1(1))q1(1) = 10 //2println(q1) //Queue(1, 10)//追加元素q1 += 20q1 ++= List(1, 2, 3)println(q1) //Queue(1, 10, 20, 1, 2, 3)
q1.enqueue(99, 98)println(q1) //Queue(1, 10, 20, 1, 2, 3, 99, 98)//删除
    q1.dequeue()println(q1) //Queue(10, 20, 1, 2, 3, 99, 98)//三个常用方法
    println(q1.head)println(q1.last)println(q1.tail)

4.6 映射 Map

    //Mapval map1 = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) //不可变println(map1) //Map(Alice -> 10, Bob -> 3, Cindy -> 8)
val map2 = mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) //可变println(map2) //Map(Bob -> 3, Alice -> 10, Cindy -> 8)
val map3 = mutable.Map(("Alice", 10), ("Bob", 3), ("Cindy", 8))println(map3) //Map(Bob -> 3, Alice -> 10, Cindy -> 8)//取值 赋值println(map1("Alice")) //10println(map1.updated("Alice", 90)) //Map(Alice -> 90, Bob -> 3, Cindy -> 8)map2("Alice") = 90 //可变集合可以直接改变值,不可变集合修改需要使用updated产生新的集合println(map1("Alice")) //10println(map2("Alice")) //90//赋值 追加map2 += ("Alice" -> 80)map2 += ("AAAA" -> 10)println(map2) //Map(Bob -> 3, AAAA -> 10, Alice -> 80, Cindy -> 8)//遍历for(m <- map2){println(m)println(m._1)println(m._2)}/*结果:(Bob,3)Bob3(AAAA,10)AAAA10(Alice,80)Alice80(Cindy,8)Cindy8*/for((k, v) <- map2){println(k + ":" + v)}/*结果:Bob:3AAAA:10Alice:80Cindy:8*/val map4 = Map("Alice" -> "AA", "Bob" -> 3, "Cindy" -> 8)  //键值可以为任意类型println(map4) //Map(Alice -> AA, Bob -> 3, Cindy -> 8)
val map5 = mutable.Map[String, Int]("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) //指定泛型println(map5) //Map(Bob -> 3, Alice -> 10, Cindy -> 8)

4.7 集 Set

    //Set//创建val set1 = Set(1, 2, 2, 3)println(set1) //Set(1, 2, 3)val set2 = mutable.Set(1, 2, 2, 3)println(set2) //Set(1, 2, 3)//取值println(set1(1)) //true //不能通过下标访问println(set1.contains(3)) //true//追加值//    set1 不能进行追加set2.add(4)println(set2) //Set(1, 2, 3, 4)
set2 += 5println(set2) //Set(1, 5, 2, 3, 4)//遍历for(s <- set2){println(s)}/*结果:15234*///删除元素set2 -= 1println(set2) //Set(5, 2, 3, 4)
set2.remove(2)println(set2) //Set(5, 3, 4)

4.8 集合元素与函数的映射

    //集合中的元素与函数之间的映射val list11 = List("Alice", "Bob", "Kotlin")val list11_1 = list11.map(x => x.toUpperCase)println(list11_1) //List(ALICE, BOB, KOTLIN)println(list11) //List(Alice, Bob, Kotlin)//等价于def f1(x: String) : String = {x.toUpperCase}val list1_3 = list11.map(f1)println(list1_3) List(Alice, Bob, Kotlin)

2)flatmap:flat 即压扁,压平,扁平化,效果就是将集合中的每个元素的子元素映射到某个函数并返回新的集合

val names = List("Alice", "Bob", "Nick")
println(names.flatMap(_.toUpperCase())) //List(A, L, I, C, E, B, O, B, N, I, C, K)

4.9 简化、折叠、扫描

1)折叠,化简:将二元函数引用于集合中的函数

val list = List(1, 2, 3, 4, 5)
val i1 = list.reduceLeft(_-_)
val i2 = list.reduceRight(_-_)println(i1)
println(i2)

笔记:

    //化简操作val list11_4 = list11.map(_.toLowerCase)println(list11_4) //List(alice, bob, kotlin)//下划线只能使用一次,x 可以多次使用。val list11_5 = list11.map(x => x.toUpperCase + x.toLowerCase)println(list11_5) //List(ALICEalice, BOBbob, KOTLINkotlin)
println(List(1,7,2,9).reduceLeft(_ - _)) //-17

    //化简,折叠,扫描val list12 = List(1, 2, 3, 4, 5)val list12_Left1 = list12.reduceLeft(_-_) //这里的两个下划线分别代表 result 和 xprintln(list12_Left1) //-13//等价于val list12_Left2 = list12.reduceLeft((result, x) => result - x)println(list12_Left2) //-13
val list12_Right1 = list12.reduceRight(_-_)println(list12_Right1) //3

2)折叠,化筒:fold

fold 函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到 list 中的所有元素被遍历。

可以把 reduceLeft 看作简化版的 foldLeft。相关函数:fold,foldLeft,foldRight,可以参考 reduce 的相关方法理解。

//fold
val list13 = List(1, 9, 2, 8)
val list13_fold1 = list13.fold(5)((sum, y) => sum + y)
val list13_fold2 = list13.fold(5)((sum, y) => sum - y)
println(list13_fold1) //25
println(list13_fold2) //-15

val list13_fold_right = list13.foldRight(100)((sum, y) => sum - y)
println(list13_fold_right) //86

提示: foldLeft 和 foldRight 有一种缩写方法对应分别是:/: 和 :\

例如:

val list4 = List(1, 9, 2, 8)
val i6 = (c /: list4)(_-_) //上一步运算的结果减下一个元素//val i6 = (c /: list4)((res, next) => res - next)
println(i6)

3)统计一句话中,各个文字出现的次数

//统计一句话中,各个文字出现的次数val sentence = "一首现代诗《笑里藏刀》:哈哈哈哈哈哈哈哈哈哈哈哈哈哈刀哈哈哈哈哈哈哈哈哈哈哈哈"val map_1 = (mutable.Map[Char, Int]() /: sentence)((m, c) => m + (c -> (m.getOrElse(c, 0) + 1)))println(map_1) //Map(代 -> 1, 笑 -> 1, 》 -> 1, 里 -> 1, 诗 -> 1, 哈 -> 26, 刀 -> 2, 首 -> 1, 《 -> 1, : -> 1, 藏 -> 1, 一 -> 1, 现 -> 1)

4)折叠,化简,扫描

这个理解需要结合上面的知识,扫描,即对某一个集合的所有元素做 fold 操作,

但是会把产生的所有中间结果放置于一个集合中保存。

val i8 = (1 to 8).scanLeft(0)(_ + _)
println(i8) //Vector(0, 1, 3, 6, 10, 15, 21, 28, 36)

化简操作:

折叠操作:

思考统计一个字符串中字符出现的频率问题。
val freq = scala.collection.mutable.Map[Char, Int]()
for (c <- "Mississippi") freq(c) = freq.getOrElse(c, 0) + 1
//或者
(Map[Char, Int]() /: "Mississippi") {(m, c) => m + (c -> (m.getOrElse(c, 0) + 1))
}

扫描操作:

扫描操作就是化简和折叠的结合。你得到包含所有中间结果的集合。 

4.10 拉链

    //拉链val zip1 = List("1893278923423", "328742917419")val zip2 = List("孙悟空", "猪八戒")val zipResultList = zip1 zip zip2println(zipResultList) //List((1893278923423,孙悟空), (328742917419,猪八戒))//封装到Map中val zipMap = mutable.Map[String, String]()for(e <- zipResultList){zipMap += e}println(zipMap) //Map(328742917419 -> 猪八戒, 1893278923423 -> 孙悟空)

4.11 迭代器

你可以通过 iterator 方法从集合获得一个迭代器,通过 while 循环和 for
表达式对集合进行遍历
val iterator = List(1, 2, 3, 4, 5).iterator
while (iter.hasNext)println(iter.next())//或:for (elem <- iter)println(elem)

4.12 流 Stream

stream是一个集合。这个集合,可以用于存放,无穷多个元素,但是这无穷个元素并不会一次性生产出来,

而是需要用到多大的区间,就会动态的生产,末尾元素遵循lazy规则

1)使用 #:: 得到一个 stream

def numsFrom(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1)

2)传递一个值,并打印 stream 集合

val tenOrMore = numsForm(10)
println(tenOrMore )

3)tail 的每一次使用,都会动态的向 stream 集合按照规则生成新的元素

println(tenOrMore.tail)
println(tenOrMore)

4)使用 map 映射 stream 的元素并进行一些计算

println(numsForm(5).map(x => x * x)) 

笔记:

//Stream
def numForm(initNum: BigInt): Stream[BigInt] = {initNum #:: numForm(initNum + 1)
}val numStream = numForm(0)
val s1 = numStream.tail //1.生成一个排除了首个元素的新集合 2.tail方法会触发stream的使用,会在调用 tail 方法的 stream 上新增元素
println(s1) //Stream(1, ?)
val s2 = s1.tail
println(s1) //Stream(1, 2, ?)
println(s2) //Stream(2, ?)
println(numStream) //Stream(0, 1, 2, ?)
println(numStream.tail) //Stream(1, 2, ?)
println(numStream.tail.tail) //Stream(2, ?)
println(numStream.tail.tail.tail) //Stream(3, ?)

val s3 = numStream.tail
val s4 = s3.tail
println(s3) //Stream(1, 2, 3, ?)
println(s4) //Stream(2, 3, ?)

4.13 视图 View

Stream 的懒执行行为,你可以对其他集合应用 view 方法来得
到类似的效果,该方法产出一个其方法总是被懒执行的集合。但是 view 不会
缓存数据,每次都要重新计算。
例如:我们找到10万以内,所有数字倒序排序还是它本身的数字
val view = (1L to 1000000L).view.map(x => x).filter(y => y.toString == y.toString.reverse)
println(view.mkString())
for(x <- view){print(x + ",")
}

 笔记:
//view
val view = (1L to 1000000L).view.map(x => x).filter(y => y.toString == y.toString.reverse)
println(view) //SeqViewMF(...)
println(view.mkString(" "))
println(view(22)) //141

4.14 线程安全的集合

所有线程安全的集合都是以 Synchronized 开头的集合,例如:

SynchronizedBuffer
SynchronizedMap
SynchronizedPriorityQueue
SynchronizedQueue
SynchronizedSet
SynchronizedStack

可以通过混入这些集合,让集合的操作变成同步的:
val scores = new scala.collection.mutable.HashMap[String,Int] with scala.collection.mutable.SynchronizedMap[String,Int]

4.15 并行集合

Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集
合),用于多核环境的并行计算。
主要用到的算法有:
divide and conquer : 分治算法
Scala 通过 splitters,combiners 等抽象层来实现,主要原理是将计算工作
分解很多任务,分发给一些处理器去完成[,并将它们处理结果合并返回]
Work stealing 算法
主要用于任务调度负载均衡(load-balancing),通俗点完成自己的所有
任务之后,发现其他人还有活没干完,主动(或被安排)帮他人一起干,这
样达到尽早干完的目的。
并行集合位于 scala.collection.parallel,跟普通集合(regular collections)一
样,分 immutable 和 mutable。主要实现类是:

1. scala.collection.parallel.mutable.ParArray
2. scala.collection.parallel.mutable.ParHashMap
3. scala.collection.parallel.mutable.ParHashSet
4.
5. scala.collection.parallel.immutable.ParRange
6. scala.collection.parallel.immutable.ParHashMap
7. scala.collection.parallel.immutable.ParHashSet
8. scala.collection.parallel.immutable.ParVector

通过 par 关键字将集合转换为一个并行集合,并行集合的类型为扩展自
ParSeq、ParSet、ParMap 特质的类型,所有特质都是 ParIterable 的子类型,
但并不是 Iterable 的子类型,所以不能将并行集合传递为预期的 Iterable、
Seq、Set 或 Map 的方法。你可以通过 ser 方法将并行集合转换回串行集合。
注意:在并行任务里面,不要同时更新一个共享变量。

1)打印 1~5
(1 to 5).foreach(println(_))
println()
(1 to 5).par.foreach(println(_))

2)查看并行集合中元素访问的线程

val result1 = (0 to 100).map{case_ => Thread.currentThread.getName}.distinct
val result2 = (0 to 100).par.map{case_ => Thread.currentThread.getName}.distinctprintln(result1) //Vector(main)println(result2) //ParVector(ForkJoinPool-1-worker-13, ForkJoinPool-1-worker-7, ForkJoinPool-1-worker-5, ForkJoinPool-1-worker-3, ForkJoinPool-1-worker-1, ForkJoinPool-1-worker-11, ForkJoinPool-1-worker-9)

4.26 操作符概述

1、如果想在变量名、类名等定义中用保留字,可以用反引号:
val `val` = 42

2、 这种形式叫中置操作符,A 操作符 B 等同于 A.操作符(B)
3、 后置操作符, A 操作符 等同于 A.操作符 ,如果操作符定义的时候不带() 则调用时不能加()
4、 前置操作符,+、-、!、~等 操作符 A 等同于 A.unary_操作符
5、 赋值操作符, A 操作符= B 等同于 A=A 操作符 B

转载于:https://www.cnblogs.com/LXL616/p/11108479.html

4.Scala-数据结构相关推荐

  1. scala数据结构之Maps和Tuples

    为什么80%的码农都做不了架构师?>>>    映射和和元组,也就是Maps和Tuples.Map这东西应该都挺明白的,就是键值对的集合.而元组,tuple,这东西并不是每个语言都有 ...

  2. Spark基础学习笔记14:Scala数据结构

    文章目录 零.本讲学习目标 一.数组 (Array) (一)定长数组 1.数组定义 (1)定义数组时初始化数据 (2)定义时指定数组长度,后赋值 2.数组遍历 (1)传统for循环方式 (2)增强fo ...

  3. array函数参数 scala_3小时Scala入门

    〇,编程环境 1,安装Java 2,配置Java环境变量 3,安装Scala 4,配置Scala环境变量 参考文末阅读原文链接. 一,算术运算 二,输入输出 输出:println,print,prin ...

  4. Scala 可变集合体系、不可变集合体系 详解

    文章目录 Scala数据结构的特点 1. Scala的集合基本介绍 2. 可变集合和不可变集合举例 不可变集合继承层次--览图 可变集合继承层次--览图 数组-定长数组(声明泛型) 1. 第一种方式定 ...

  5. scala基础(一)

    Scala 编程 -Scala基础 1.课程目标 安装Scala编译和运行环境 熟悉Scala基本语法以及函数式编程 熟练掌握Scala数据结构使用以及集合方法操作 2.Scala基础 2.1Scal ...

  6. 好久不见!!菜鸟学习笔记之Scala学习笔记(部分),持续更新~~

    文章目录 Scala简介 快速入门之HelloWorld IDEA开发Scala 工程创建 Scala开发规范 Scala基础语言学习 Chap01.内容输出与文档查看 Chap02.变量 2.1 声 ...

  7. 2022年Spark基础学习笔记目录

    一.Spark学习笔记 在私有云上创建与配置虚拟机 Spark基础学习笔记01:初步了解Spark Spark基础学习笔记02:Spark运行时架构 Spark基础学习笔记03:搭建Spark单机版环 ...

  8. Spark复习大纲,有需要的小伙伴可以点个赞找我私信

    REVIEW COVER: chapt1-chapt6 QUESTION TYPE: 选择,填空,简答,阅读程序(写结果),编程题(代码补全) Chap1 Hadoop 生态系统的组件 Hadoop除 ...

  9. 尚硅谷YYDS (课件资料)

    面试大保健 链接:https://pan.baidu.com/s/1duUHb4AwOnW9jycDnUCRVA 提取码:undf 尚硅谷大数据技术之 StarRocks 链接:https://pan ...

  10. 【从零开始的大数据学习】Flink官方教程学习笔记(一)

    Flink官方教程学习笔记 学习资源 基础Scala语法 Scala数据结构专题 声明变量 代码块 函数(function) 方法(methods) Traits (接口) class(类) tupl ...

最新文章

  1. mysql pma用户_MYSQL用户权限管理学习笔记
  2. Windows IIS注册asp 此操作系统版本不支持此选项 错误解决方法
  3. 自定义SpringBoot项目的Maven原型
  4. Quibi:我轻轻地咬一口 你最爱的Netflix和TikTok
  5. 手把手教你研发属于自己的智能无人机
  6. python异常值如何处理_如何处理异常
  7. java 工程新建ivy文件_Hadoop学习之路(八)在eclispe上搭建Hadoop开发环境
  8. 探讨SEO与前端:使用display:none对seo的影响
  9. STM32H743+CubeMX-SPI与DRV8889串行通讯,驱动步进电机
  10. 2019中国民营企业500强发布:华为、海航、苏宁位列前三
  11. 开发者须知:关于 Android L 的一切
  12. java calendar类_Java世界最常用的工具类库
  13. PCL中3D点云特征描述与提取(一)
  14. SSM+家装管理系统 毕业设计-附源码191452
  15. 【3D目标检测】PV-RCNN:Point-Voxel Feature Set Abstraction for 3D Object Detection
  16. 企业的病毒,要及时清理
  17. 利用存儲過程進行簡繁體轉換
  18. 下列叙述中正确的是计算机课,大学计算机课程练习题(期末)
  19. 做好多项目管理的十个关键步骤(含工具)
  20. 安装网页书签收藏夹Shiori

热门文章

  1. butterknife 配置了点击和绑定无效
  2. Java开发中的23种设计模式
  3. 系统简单的UIImagePickerController
  4. 使用BIND安装智能DNS服务器(三)---添加view和acl配置
  5. Jsp 【项目路径】
  6. cocos-2d iphone入门(二) cocos2d源代码生成查询文档
  7. 如何使用VC6.0创建DLL
  8. 【模型压缩系列】一:模型替换
  9. 【结巴分词】浅谈结巴分词算法原理
  10. 【从 0 开始机学习】正则化技术原理与编程!