Scala 系列(六)—— 常用集合类型之 List & Set
一、List字面量
List 是 Scala 中非常重要的一个数据结构,其与 Array(数组) 非常类似,但是 List 是不可变的,和 Java 中的 List 一样,其底层实现是链表。
scala> val list = List("hadoop", "spark", "storm")
list: List[String] = List(hadoop, spark, storm)
// List 是不可变
scala> list(1) = "hive"
<console>:9: error: value update is not a member of List[String]
二、List类型
Scala 中 List 具有以下两个特性:
- 同构 (homogeneous):同一个 List 中的所有元素都必须是相同的类型;
- 协变 (covariant):如果 S 是 T 的子类型,那么
List[S]
就是List[T]
的子类型,例如List[String]
是List[Object]
的子类型。
需要特别说明的是空列表的类型为 List[Nothing]
:
scala> List()
res1: List[Nothing] = List()
三、构建List
所有 List 都由两个基本单元构成:Nil
和 ::
(读作"cons")。即列表要么是空列表 (Nil),要么是由一个 head 加上一个 tail 组成,而 tail 又是一个 List。我们在上面使用的 List("hadoop", "spark", "storm")
最终也是被解释为 "hadoop"::"spark":: "storm"::Nil
。
scala> val list01 = "hadoop"::"spark":: "storm"::Nil
list01: List[String] = List(hadoop, spark, storm)
// :: 操作符号是右结合的,所以上面的表达式和下面的等同
scala> val list02 = "hadoop"::("spark":: ("storm"::Nil))
list02: List[String] = List(hadoop, spark, storm)
四、模式匹配
Scala 支持展开列表以实现模式匹配。
scala> val list = List("hadoop", "spark", "storm")
list: List[String] = List(hadoop, spark, storm)
scala> val List(a,b,c)=list
a: String = hadoop
b: String = spark
c: String = storm
如果只需要匹配部分内容,可以如下:
scala> val a::rest=list
a: String = hadoop
rest: List[String] = List(spark, storm)
五、列表的基本操作
5.1 常用方法
object ScalaApp extends App {
val list = List("hadoop", "spark", "storm")
// 1.列表是否为空
list.isEmpty
// 2.返回列表中的第一个元素
list.head
// 3.返回列表中除第一个元素外的所有元素 这里输出 List(spark, storm)
list.tail
// 4.tail 和 head 可以结合使用
list.tail.head
// 5.返回列表中的最后一个元素 与 head 相反
list.init
// 6.返回列表中除了最后一个元素之外的其他元素 与 tail 相反 这里输出 List(hadoop, spark)
list.last
// 7.使用下标访问元素
list(2)
// 8.获取列表长度
list.length
// 9. 反转列表
list.reverse
}
5.2 indices
indices 方法返回所有下标。
scala> list.indices
res2: scala.collection.immutable.Range = Range(0, 1, 2)
5.3 take & drop & splitAt
- take:获取前 n 个元素;
- drop:删除前 n 个元素;
- splitAt:从第几个位置开始拆分。
scala> list take 2
res3: List[String] = List(hadoop, spark)
scala> list drop 2
res4: List[String] = List(storm)
scala> list splitAt 2
res5: (List[String], List[String]) = (List(hadoop, spark),List(storm))
5.4 flatten
flatten 接收一个由列表组成的列表,并将其进行扁平化操作,返回单个列表。
scala> List(List(1, 2), List(3), List(), List(4, 5)).flatten
res6: List[Int] = List(1, 2, 3, 4, 5)
5.5 zip & unzip
对两个 List 执行 zip
操作结果如下,返回对应位置元素组成的元组的列表,unzip
则执行反向操作。
scala> val list = List("hadoop", "spark", "storm")
scala> val score = List(10,20,30)
scala> val zipped=list zip score
zipped: List[(String, Int)] = List((hadoop,10), (spark,20), (storm,30))
scala> zipped.unzip
res7: (List[String], List[Int]) = (List(hadoop, spark, storm),List(10, 20, 30))
5.6 toString & mkString
toString 返回 List 的字符串表现形式。
scala> list.toString
res8: String = List(hadoop, spark, storm)
如果想改变 List 的字符串表现形式,可以使用 mkString。mkString 有三个重载方法,方法定义如下:
// start:前缀 sep:分隔符 end:后缀
def mkString(start: String, sep: String, end: String): String =
addString(new StringBuilder(), start, sep, end).toString
// seq 分隔符
def mkString(sep: String): String = mkString("", sep, "")
// 如果不指定分隔符 默认使用""分隔
def mkString: String = mkString("")
使用示例如下:
scala> list.mkString
res9: String = hadoopsparkstorm
scala> list.mkString(",")
res10: String = hadoop,spark,storm
scala> list.mkString("{",",","}")
res11: String = {hadoop,spark,storm}
5.7 iterator & toArray & copyToArray
iterator 方法返回的是迭代器,这和其他语言的使用是一样的。
object ScalaApp extends App {
val list = List("hadoop", "spark", "storm")
val iterator: Iterator[String] = list.iterator
while (iterator.hasNext) {
println(iterator.next)
}
}
toArray 和 toList 用于 List 和数组之间的互相转换。
scala> val array = list.toArray
array: Array[String] = Array(hadoop, spark, storm)
scala> array.toList
res13: List[String] = List(hadoop, spark, storm)
copyToArray 将 List 中的元素拷贝到数组中指定位置。
object ScalaApp extends App {
val list = List("hadoop", "spark", "storm")
val array = Array("10", "20", "30")
list.copyToArray(array,1)
println(array.toBuffer)
}
// 输出 :ArrayBuffer(10, hadoop, spark)
六、列表的高级操作
6.1 列表转换:map & flatMap & foreach
map 与 Java 8 函数式编程中的 map 类似,都是对 List 中每一个元素执行指定操作。
scala> List(1,2,3).map(_+10)
res15: List[Int] = List(11, 12, 13)
flatMap 与 map 类似,但如果 List 中的元素还是 List,则会对其进行 flatten 操作。
scala> list.map(_.toList)
res16: List[List[Char]] = List(List(h, a, d, o, o, p), List(s, p, a, r, k), List(s, t, o, r, m))
scala> list.flatMap(_.toList)
res17: List[Char] = List(h, a, d, o, o, p, s, p, a, r, k, s, t, o, r, m)
foreach 要求右侧的操作是一个返回值为 Unit 的函数,你也可以简单理解为执行一段没有返回值代码。
scala> var sum = 0
sum: Int = 0
scala> List(1, 2, 3, 4, 5) foreach (sum += _)
scala> sum
res19: Int = 15
6.2 列表过滤:filter & partition & find & takeWhile & dropWhile & span
filter 用于筛选满足条件元素,返回新的 List。
scala> List(1, 2, 3, 4, 5) filter (_ % 2 == 0)
res20: List[Int] = List(2, 4)
partition 会按照筛选条件对元素进行分组,返回类型是 tuple(元组)。
scala> List(1, 2, 3, 4, 5) partition (_ % 2 == 0)
res21: (List[Int], List[Int]) = (List(2, 4),List(1, 3, 5))
find 查找第一个满足条件的值,由于可能并不存在这样的值,所以返回类型是 Option
,可以通过 getOrElse
在不存在满足条件值的情况下返回默认值。
scala> List(1, 2, 3, 4, 5) find (_ % 2 == 0)
res22: Option[Int] = Some(2)
val result: Option[Int] = List(1, 2, 3, 4, 5) find (_ % 2 == 0)
result.getOrElse(10)
takeWhile 遍历元素,直到遇到第一个不符合条件的值则结束遍历,返回所有遍历到的值。
scala> List(1, 2, 3, -4, 5) takeWhile (_ > 0)
res23: List[Int] = List(1, 2, 3)
dropWhile 遍历元素,直到遇到第一个不符合条件的值则结束遍历,返回所有未遍历到的值。
// 第一个值就不满足条件,所以返回列表中所有的值
scala> List(1, 2, 3, -4, 5) dropWhile (_ < 0)
res24: List[Int] = List(1, 2, 3, -4, 5)
scala> List(1, 2, 3, -4, 5) dropWhile (_ < 3)
res26: List[Int] = List(3, -4, 5)
span 遍历元素,直到遇到第一个不符合条件的值则结束遍历,将遍历到的值和未遍历到的值分别放入两个 List 中返回,返回类型是 tuple(元组)。
scala> List(1, 2, 3, -4, 5) span (_ > 0)
res27: (List[Int], List[Int]) = (List(1, 2, 3),List(-4, 5))
6.3 列表检查:forall & exists
forall 检查 List 中所有元素,如果所有元素都满足条件,则返回 true。
scala> List(1, 2, 3, -4, 5) forall ( _ > 0 )
res28: Boolean = false
exists 检查 List 中的元素,如果某个元素已经满足条件,则返回 true。
scala> List(1, 2, 3, -4, 5) exists (_ > 0 )
res29: Boolean = true
6.4 列表排序:sortWith
sortWith 对 List 中所有元素按照指定规则进行排序,由于 List 是不可变的,所以排序返回一个新的 List。
scala> List(1, -3, 4, 2, 6) sortWith (_ < _)
res30: List[Int] = List(-3, 1, 2, 4, 6)
scala> val list = List( "hive","spark","azkaban","hadoop")
list: List[String] = List(hive, spark, azkaban, hadoop)
scala> list.sortWith(_.length>_.length)
res33: List[String] = List(azkaban, hadoop, spark, hive)
七、List对象的方法
上面介绍的所有方法都是 List 类上的方法,下面介绍的是 List 伴生对象中的方法。
7.1 List.range
List.range 可以产生指定的前闭后开区间内的值组成的 List,它有三个可选参数: start(开始值),end(结束值,不包含),step(步长)。
scala> List.range(1, 5)
res34: List[Int] = List(1, 2, 3, 4)
scala> List.range(1, 9, 2)
res35: List[Int] = List(1, 3, 5, 7)
scala> List.range(9, 1, -3)
res36: List[Int] = List(9, 6, 3)
7.2 List.fill
List.fill 使用指定值填充 List。
scala> List.fill(3)("hello")
res37: List[String] = List(hello, hello, hello)
scala> List.fill(2,3)("world")
res38: List[List[String]] = List(List(world, world, world), List(world, world, world))
7.3 List.concat
List.concat 用于拼接多个 List。
scala> List.concat(List('a', 'b'), List('c'))
res39: List[Char] = List(a, b, c)
scala> List.concat(List(), List('b'), List('c'))
res40: List[Char] = List(b, c)
scala> List.concat()
res41: List[Nothing] = List()
八、处理多个List
当多个 List 被放入同一个 tuple 中时候,可以通过 zipped 对多个 List 进行关联处理。
// 两个 List 对应位置的元素相乘
scala> (List(10, 20), List(3, 4, 5)).zipped.map(_ * _)
res42: List[Int] = List(30, 80)
// 三个 List 的操作也是一样的
scala> (List(10, 20), List(3, 4, 5), List(100, 200)).zipped.map(_ * _ + _)
res43: List[Int] = List(130, 280)
// 判断第一个 List 中元素的长度与第二个 List 中元素的值是否相等
scala> (List("abc", "de"), List(3, 2)).zipped.forall(_.length == _)
res44: Boolean = true
九、缓冲列表ListBuffer
上面介绍的 List,由于其底层实现是链表,这意味着能快速访问 List 头部元素,但对尾部元素的访问则比较低效,这时候可以采用 ListBuffer
,ListBuffer 提供了在常量时间内往头部和尾部追加元素。
import scala.collection.mutable.ListBuffer
object ScalaApp extends App {
val buffer = new ListBuffer[Int]
// 1.在尾部追加元素
buffer += 1
buffer += 2
// 2.在头部追加元素
3 +=: buffer
// 3. ListBuffer 转 List
val list: List[Int] = buffer.toList
println(list)
}
//输出:List(3, 1, 2)
十、集(Set)
Set 是不重复元素的集合。分为可变 Set 和不可变 Set。
10.1 可变Set
object ScalaApp extends App {
// 可变 Set
val mutableSet = new collection.mutable.HashSet[Int]
// 1.添加元素
mutableSet.add(1)
mutableSet.add(2)
mutableSet.add(3)
mutableSet.add(3)
mutableSet.add(4)
// 2.移除元素
mutableSet.remove(2)
// 3.调用 mkString 方法 输出 1,3,4
println(mutableSet.mkString(","))
// 4. 获取 Set 中最小元素
println(mutableSet.min)
// 5. 获取 Set 中最大元素
println(mutableSet.max)
}
10.2 不可变Set
不可变 Set 没有 add 方法,可以使用 +
添加元素,但是此时会返回一个新的不可变 Set,原来的 Set 不变。
object ScalaApp extends App {
// 不可变 Set
val immutableSet = new collection.immutable.HashSet[Int]
val ints: HashSet[Int] = immutableSet+1
println(ints)
}
// 输出 Set(1)
10.3 Set间操作
多个 Set 之间可以进行求交集或者合集等操作。
object ScalaApp extends App {
// 声明有序 Set
val mutableSet = collection.mutable.SortedSet(1, 2, 3, 4, 5)
val immutableSet = collection.immutable.SortedSet(3, 4, 5, 6, 7)
// 两个 Set 的合集 输出:TreeSet(1, 2, 3, 4, 5, 6, 7)
println(mutableSet ++ immutableSet)
// 两个 Set 的交集 输出:TreeSet(3, 4, 5)
println(mutableSet intersect immutableSet)
}
参考资料
- Martin Odersky . Scala 编程 (第 3 版)[M] . 电子工业出版社 . 2018-1-1
- 凯.S.霍斯特曼 . 快学 Scala(第 2 版)[M] . 电子工业出版社 . 2017-7
更多大数据系列文章可以参见 GitHub 开源项目: 大数据入门指南
Scala 系列(六)—— 常用集合类型之 List & Set的更多相关文章
- Scala 学习之路(六)—— 常用集合类型之 List & Set
一.List字面量 List是Scala中非常重要的一个数据结构,其与Array(数组)非常类似,但是List是不可变的,和Java中的List一样,其底层实现是链表. scala> val l ...
- Scala 系列(七)—— 常用集合类型之 Map & Tuple
一.映射(Map) 1.1 构造Map // 初始化一个空 map val scores01 = new HashMap[String, Int] // 从指定的值初始化 Map(方式一) val s ...
- Scala 学习之路(七)—— 常用集合类型之 Map & Tuple
一.映射(Map) 1.1 构造Map // 初始化一个空map val scores01 = new HashMap[String, Int] // 从指定的值初始化Map(方式一) val sco ...
- C# 各种常用集合类型的线程安全版本
在C#里面我们常用各种集合,数组,List,Dictionary,Stack等,然而这些集合都是非线程安全的,当多线程同时读写这些集合的时候,有可能造成里面的数据混乱,为此微软从Net4.0开始专门提 ...
- Java中的常用集合类型总结
1.可重复列表(List) LinkedList和ArrayList的区别:http://www.importnew.com/6629.html ArrayList vs. LinkedList vs ...
- java 常用集合类型--以及其特性
1:集合: (1) Collection(单列集合) List(有序,可重复) ArrayList 底层数据结构是数组,查询快,增 ...
- Scala 系列(五)—— 集合类型综述
一.集合简介 Scala中拥有多种集合类型,主要分为可变的和不可变的集合两大类: 可变集合: 可以被修改.即可以更改,添加,删除集合中的元素: 不可变集合类:不能被修改.对集合执行更改,添加或删除操作 ...
- Scala集合类型详解
Scala集合 Scala提供了一套很好的集合实现,提供了一些集合类型的抽象. Scala 集合分为可变的和不可变的集合. 可变集合可以在适当的地方被更新或扩展.这意味着你可以修改,添加,移除一个集合 ...
- Scala 学习之路(五)—— 集合类型综述
一.集合简介 Scala中拥有多种集合类型,主要分为可变的和不可变的集合两大类: 可变集合: 可以被修改.即可以更改,添加,删除集合中的元素: 不可变集合类:不能被修改.对集合执行更改,添加或删除操作 ...
随机推荐
- C#7.1 新增功能
连载目录 [已更新最新开发文章,点击查看详细] C# 7.1 是 C# 语言的第一个点版本(更新版本). 它标志着该语言发布节奏的加速. 理想情况下,可以在每个新功能准备就绪时更快推出新功能. ...
- Flume+Kafka收集Docker容器内分布式日志应用实践
1 背景和问题 随着云计算.PaaS平台的普及,虚拟化.容器化等技术的应用,例如Docker等技术,越来越多的服务会部署在云端.通常,我们需要需要获取日志,来进行监控.分析.预测.统计等工作,但是云端 ...
- spring中获取容器中的Bean为什么前转成接口而不是实现类
简单介绍一下上下文,userService是服务层接口有一个save方法,userServiceImpl是该接口的实现类重写了save方法. applicationContext.xml如图: 后台代 ...
- Win常用软件
本节只适合windows系统 VScode 下载 安装 双击安装 打开目录方式 右键文件夹->使用VSCode打开 命令行打开 code folder [dzlua@win10:~]$ ls a ...
- 【Python-Django】Jinja2模板引擎配置教程详解!!!!
Jinjia2的官方文档:http://jinja.pocoo.org/docs/2.10/ 1. 安装Jinja2扩展包 $ pip install Jinja2 2. 配置Jinja2模板引擎 T ...
- dubbo异常处理
dubbo异常处理 我们的项目使用了dubbo进行不同系统之间的调用. 每个项目都有一个全局的异常处理,对于业务异常,我们会抛出自定义的业务异常(继承RuntimeException). 全局的异常处 ...
- Java equal() 和 == 详细分析
1 == 返回值是true/false; (1) 基本数据类型比较的就是值(2)引用型数据类型就是地址值 public class Test1 { public static void main(S ...
- codeforces1088D_Ehab and another another xor problem交互题
传送门 一道考验思维的交互题 大致思路就是从最高的二进制位向下询问 代入例子比如: 5 6 6 5 7 4 6 4 讨论一下 交互题的重点学会推理和归纳 #include <bits/stdc+ ...
- 数据结构之稀疏矩阵C++版
//只是简单的演示一下,这个实际运用视乎不怎么多,所以java版不再实现 /* 希疏矩阵应用于对数据的压缩,仅仅保留不为0的数据 稀疏矩阵的转置,可以由多种方式,下面演示的稍显简单,时间复杂度略高O( ...
- Starling 环形进度条实现
项目初期想实现这个效果来着,查了很多资料(包括式神的<神奇的滤镜>),也没找到完美的实现方法,,当时时间紧迫,就找了传统的进度条来代替实现. 最近偶然心血来潮,查了各方面资料,终于找到实现 ...