Scala 容器类(一)
Mutable和ImMutable
scala.collection包含可变和不可变。eg:collection.IndexedSeq[T]] 就是 collection.immutable.IndexedSeq[T]和collection.mutable.IndexedSeq[T]这两类的超类,只是mutable包在immutable包的基础上添加了一些辅助性的修改操作。
mutable (可变集合)
- 可以在适当的地方被更新或扩展,可以修改,添加,移除一个集合的元素。
- 如果想要同时使用可变和不可变集合类,只导入collection.mutable包即可。
- mutable 集合类继承关系
immutable (不可变集合)
- 不会被改变。但仍可以进行模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
- 默认情况之下,使用不可变集合类。
- immutable 集合类继承关系
Trait Traversable
Traversable(遍历)是容器(collection)类的最高级别特性(trait),它唯一的抽象操作是foreach:
def foreach[U](f: Elem => U)
需要实现Traversable的容器(collection)类仅仅需要定义与之相关的方法,其他所有方法可都可以从Traversable中继承。
foreach方法用于遍历容器(collection)内的所有元素和每个元素进行指定的操作(比如说f操作)。操作类型是Elem => U,其中Elem是容器(collection)中元素的类型,U是一个任意的返回值类型。对f的调用仅仅是容器遍历的副作用,实际上所有函数f的计算结果都被foreach抛弃了。
Traversable同时定义的很多具体方法,如下表所示。这些方法可以划分为以下类别:
- 相加操作++(addition)表示把两个traversable对象附加在一起或者把一个迭代器的所有元素添加到traversable对象的尾部。
- Map操作有map,flatMap和collect,它们可以通过对容器中的元素进行某些运算来生成一个新的容器。
- 转换器(Conversion)操作包括toArray,toList,toIterable,toSeq,toIndexedSeq,toStream,toSet,和toMap,它们可以按照某种特定的方法对一个Traversable 容器进行转换。等容器类型已经与所需类型相匹配的时候,所有这些转换器都会不加改变的返回该容器。例如,对一个list使用toList,返回的结果就是list本身。
- 拷贝(Copying)操作有copyToBuffer和copyToArray。从字面意思就可以知道,它们分别用于把容器中的元素元素拷贝到一个缓冲区或者数组里。
- Size info操作包括有isEmpty,nonEmpty,size和hasDefiniteSize。Traversable容器有有限和无限之分。比方说,自然数流Stream.from(0)就是一个无限的traversable 容器。hasDefiniteSize方法能够判断一个容器是否可能是无限的。若hasDefiniteSize返回值为ture,容器肯定有限。若返回值为false,根据完整信息才能判断容器(collection)是无限还是有限。
- 元素检索(ElementRetrieval) 操作有head,last,headOption,lastOption和find。这些操作可以查找容器的第一个元素或者最后一个元素,或者第一个符合某种条件的元素。注意,尽管如此,但也不是所有的容器都明确定义了什么是“第一个”或”最后一个“。例如,通过哈希值储存元素的哈希集合(hashSet),每次运行哈希值都会发生改变。在这种情况下,程序每次运行都可能会导致哈希集合的”第一个“元素发生变化。如果一个容器总是以相同的规则排列元素,那这个容器是有序的。大多数容器都是有序的,但有些不是(例如哈希集合)– 排序会造成一些额外消耗。排序对于重复性测试和辅助调试是不可或缺的。这就是为什么Scala容器中的所有容器类型都把有序作为可选项。例如,带有序性的HashSet就是LinkedHashSet。
- 子容器检索(sub-collection Retrieval) 操作有tail,init,slice,take,drop,takeWhilte,dropWhile,filter,filteNot和withFilter。它们都可以通过范围索引或一些论断的判断返回某些子容器。
- 拆分(Subdivision)操作有splitAt,span,partition和groupBy,它们用于把一个容器(collection)里的元素分割成多个子容器。
- 元素测试(Element test) 包括有exists,forall和count,它们可以用一个给定论断来对容器中的元素进行判断。
- 折叠(Folds)操作有foldLeft,foldRight,/:,:\,reduceLeft和reduceRight,用于对连续性元素的二进制操作。
- 特殊折叠(Specific folds)包括sum, product, min, max。它们主要用于特定类型的容器(数值或比较)。
- 字符串(String)操作有mkString,addString和stringPrefix,可以将一个容器通过可选的方式转换为字符串。
- 视图(View)操作包含两个view方法的重载体。一个view对象可以当作是一个容器客观地展示。接下来将会介绍更多有关视图内容。
TRAIT ITERABLE
容器(collection)结构的上层还有另一个trait。这个trait里所有方法的定义都基于一个抽象方法,迭代器(iterator,会逐一的产生集合的所有元素)。从Traversable trait里继承来的foreach方法在这里也是利用iterator实现。下面是具体的实现。
def foreach[U](f: Elem => U): Unit = {
val it = iterator
while (it.hasNext) f(it.next())
}
foreach是Traversable所有操作的基础,所以它的性能表现很关键。
Iterable有两个方法返回迭代器:grouped和sliding。这些迭代器返回的不是单个元素,而是原容器(collection)元素的全部子序列。grouped方法返回元素的增量分块,sliding方法生成一个滑动元素的窗口。
Trait Iterable操作
抽象方法: | |
---|---|
xs.iterator | xs迭代器生成的每一个元素,以相同的顺序就像foreach一样遍历元素 |
其他迭代器: | |
xs grouped size | 一个迭代器生成一个固定大小的容器(collection)块 |
xs sliding size | 一个迭代器生成一个固定大小的滑动窗口作为容器(collection)的元素 |
子容器(Subcollection): | |
xs takeRight n | 一个由xs的最后n个元素组成的collection(若定义的元素是无序,则由任意的n个元素组成) |
xs dropRight n | 一个由除了xs被取走(执行takeRight()方法) n个元素外的其余元素组成的collection |
拉链方法(Zippers): | |
xs zip ys | 把一对容器 xs和ys的包含的元素合成到一个iterabale |
xs zipAll(ys, x, y) | 一对容器 xs 和ys的相应的元素合并到一个iterable ,实现方式是通过附加的元素x或y,把短的序列被延展到相对更长的一个上 |
xs.zip WithIndex | 把一对容器xs和它的序列,所包含的元素组成一个iterable |
比对: | |
xs sameElements ys | 测试 xs 和 ys 是否以相同的顺序包含相同的元素 |
REPL:
//iterator
scala> val a = List(1,2,3,4,5)
a: List[Int] = List(1, 2, 3, 4, 5)
scala> val aIterator = a.iterator
aIterator: Iterator[Int] = <iterator>
scala> aIterator.next()
res3: Int = 1
scala> aIterator.next()
res4: Int = 2
//grouped
scala> val a = List(1,2,3,4,5)
a: List[Int] = List(1, 2, 3, 4, 5)
scala> val aIterator = a grouped 2
aIterator: Iterator[List[Int]] = <iterator>
scala> aIterator.next()
res0: List[Int] = List(1, 2)
scala> aIterator.next()
res1: List[Int] = List(3, 4)
scala> aIterator.next()
res2: List[Int] = List(5)
//sliding
scala> val aIterator = a sliding 2
aIterator: Iterator[List[Int]] = <iterator>
scala> aIterator.next()
res5: List[Int] = List(1, 2)
scala> aIterator.next()
res6: List[Int] = List(2, 3)
scala> aIterator.next()
res7: List[Int] = List(3, 4)
//takeRight
scala> val aSubcollection = a takeRight 3
aSubcollection: List[Int] = List(3, 4, 5)
//dropRight
scala> val aSubcollection = a dropRight 2
aSubcollection: List[Int] = List(1, 2, 3)
scala> val aSubcollection = a dropRight 3
aSubcollection: List[Int] = List(1, 2)
//zip
scala> val b = List("a","b","c","d","e","f")
b: List[String] = List(a, b, c, d, e, f)
scala> val sum = a zip b
sum: List[(Int, String)] = List((1,a), (2,b), (3,c), (4,d), (5,e)) //这里结果舍去了 “f”
//zipAll
scala> val sumAll = a zipAll(b,6,"z")
sumAll: List[(Int, String)] = List((1,a), (2,b), (3,c), (4,d), (5,e), (6,f))
//zipWithIndex
scala> b.zipWithIndex
res9: List[(String, Int)] = List((a,0), (b,1), (c,2), (d,3), (e,4), (f,5))
//sameElements
scala> a sameElements b
res10: Boolean = false
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗