Scala 容器类(三)
Set
集合是不包含重复元素的可迭代对象。
Set 类的操作
操作 | 说明 |
---|---|
xs subsetOf ys | 测试 xs 是否是 ys 的子集 |
xs ++ ys | 包含 xs 中所有元素及 ys 中所有元素的集合 |
xs -- ys | xs 中所有元素,去掉 ys 中所有元素后剩下的部分 |
xs.empty | 与 xs 同类的空集合(非xs) |
xs &~ ys | 集合 xs 和 ys 的差集 |
mutable.Set 类的操作
操作 | 说明 |
---|---|
xs ++= ys | 添加集合 ys 中的所有元素到集合 xs 中,并返回 xs 本身。(表达式有副作用) |
xs add x | 把元素 x 添加到集合 xs 中,如集合 xs 之前没有包含 x,该操作返回 true,否则返回 false |
xs retain p | 只保留集合 xs 中满足条件 p 的元素 |
xs.clear() | 删除集合 xs 中的所有元素 |
xs(x) = b/xs.update(x, b) | 参数 b 为布尔类型,如果值为 true 就把元素x加入集合 xs,否则从集合 xs 中删除 x |
可变集合和不可变集合提供了+和++操作符来添加元素,-和--用来删除元素。但是这些操作在可变集合中通常很少使用,因为这些操作都要通过集合的拷贝来实现。更有效率的方法是+=和-=,另外还有批量操作符++=和--=。
目前可变集合默认使用哈希表来存储集合元素,非可变集合则根据元素个数的不同,使用不同的方式来实现。空集用单例对象来表示。元素个数小于等于4的集合可以使用单例对象来表达,元素作为单例对象的字段来存储。 元素超过4个,非可变集合就用哈希前缀树(hash trie)来实现。
采用这种表示方法,较小的不可变集合(元素数不超过4)往往会比可变集合更加紧凑和高效。所以,在处理小尺寸的集合时,不妨试试不可变集合。
集合的两个特质是 SortedSet 和 BitSet.
SortedSet
SortedSet 是指以特定的顺序(可以在创建集合时设置顺序)排列其元素(使用iterator或foreach)的集合,默认表示是有序二叉树,即左子树上的元素小于所有右子树上的元素。这样,一次简单的顺序遍历能按增序返回集合中的所有元素。Scala的类 immutable.TreeSet 使用红黑树实现,它在维护元素顺序的同时,也会保证二叉树的平衡,即叶节点的深度差最多为1。
创建一个新的TreeSet,可以先定义排序规则,然后利用排序规则创建树集。
val myOrdering = Ordering.fromLessThan[Int](_ < _)
TreeSet.empty(myOrdering)
或者,也可以不指定排序规则参数,只需要给定一个元素类型或空集合。在这种情况下,将使用此元素类型默认的排序规则。
TreeSet.empty[String]
BitSet
BitSet是由单字或多字的紧凑位实现的非负整数的集合。其内部使用 Long 型数组来表示。第一个 Long 元素表示的范围为0到63,第二个范围为64到127,以此类推(值为0到127的非可变位集合通过直接将值存储到第一个或第两个 Long 字段的方式,优化掉了数组处理的消耗)。对于每个 Long,如果有相应的值包含于集合中则它对应的位设置为1,否则该位为0。
位集合的大小取决于存储在该集合的最大整数的值的大小。假如N是为集合所要表示的最大整数,则集合的大小就是 N/64 个长整形字,或者 N/8 个字节,再加上少量额外的状态信息字节。
当位集合包含的元素值都比较小时,它比其他的集合类型更紧凑。位集合的另一个优点是它的 contains 方法(成员测试)、+= 运算(添加元素)、-= 运算(删除元素)都非常的高效。
Map
Map是一种可迭代的键值对结构。Scala的Predef类提供了隐式转换,允许使用另一种语法:key -> value 代替(key,value)
Map类的操作
操作 | 说明 |
---|---|
查询操作 | |
ms get k | 返回一个Option,其中包含和键k关联的值。若k不存在,则返回None |
ms(k) | (完整写法是ms apply k)返回和键k关联的值。若k不存在,则抛出异常 |
ms getOrElse (k, d) | 返回和键k关联的值。若k不存在,则返回默认值d |
ms contains k | 检查ms是否包含与键k相关联的映射 |
ms isDefinedAt k | 同contains |
添加及更新 | |
ms + (k -> v) | 返回一个同时包含ms中所有键值对及从k到v的键值对k -> v的新映射 |
ms ++ kvs | 返回一个同时包含ms中所有键值对及kvs中的所有键值对的新映射 |
ms updated (k, v) | 同ms + (k -> v) |
移除 | |
ms - k | 返回一个包含ms中除键k以外的所有映射关系的映射 |
ms - (k, 1, m) | 返回一个滤除了ms中与所有给定的键相关联的映射关系的新映射 |
ms - ks | |
子容器 | |
ms.keys | 返回一个用于包含ms中所有键的iterable对象(注意iterable对象与iterator的区别) |
ms.keySet | 返回一个包含ms中所有的键的Set |
ms.keysIterator | 返回一个用于遍历ms中所有key的迭代器 |
ms.values | 返回一个包含ms中所有值的iterable对象 |
ms.valuesIterator | 返回一个用于遍历ms中所有值的迭代器 |
变换 | |
ms filterKeys p | 一个映射视图(Map View),其包含一些ms中的映射,且这些映射的键满足条件p。用条件谓词p过滤ms中所有的键,返回一个仅包含与过滤出的键值对的映射视图 |
ms mapValues f | 用f将ms中每一个键值对的值转换成一个新的值,进而返回一个包含所有新键值对的映射视图 |
这里只练习几个陌生的操作。
REPL:
scala> val ms = Map(1->"a",2->"b",3->"c")
ms: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b, 3 -> c)
scala> ms.contains(3)
res0: Boolean = true
scala> ms.isDefinedAt(1)
res2: Boolean = true
scala> ms.keys
res6: Iterable[Int] = Set(1, 2, 3)
scala> ms.keySet
res7: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
scala> ms.keysIterator
res8: Iterator[Int] = <iterator>
scala> res8.next()
res9: Int = 1
scala> res8.next()
res10: Int = 2
scala> ms.valuesIterator
res12: Iterator[String] = <iterator>
scala> ms.view.filterKeys(_>=1) //用ms.view.filterKeys 代替 ms.filterKeys
res14: scala.collection.MapView[Int,String] = MapView(<not computed>)
mutable.Map类的操作
操作 | 说明 |
---|---|
添加及更新 | |
ms(k) = v | (完整形式为ms.update(x, v))。向映射ms中新增一个以k为键、以v为值的映射关系,ms先前包含的以k为值的映射关系将被覆盖 |
ms += (k -> v) | 向映射ms增加一个以k为键、以v为值的映射关系,并返回ms自身 |
ms += (k -> v, l -> w) | 向映射ms中增加给定的多个映射关系,并返回ms自身 |
ms ++= kvs | 向映射ms增加kvs中的所有映射关系,并返回ms自身 |
ms put (k, v) | 向映射ms增加一个以k为键、以v为值的映射,并返回一个Option,其中可能包含此前与k相关联的值 |
ms getOrElseUpdate (k, d) | 如果ms中存在键k,则返回键k的值。否则向ms中新增映射关系k -> v并返回d |
移除 | |
ms -= k | 从映射ms中删除以k为键的映射关系,并返回ms自身 |
ms -= (k, l, m) | 从映射ms中删除与给定的各个键相关联的映射关系,并返回ms自身 |
ms –= ks | 从映射ms中删除与ks给定的各个键相关联的映射关系,并返回ms自身 |
ms remove k | 从ms中移除以k为键的映射关系,并返回一个Option,其可能包含之前与k相关联的值 |
ms retain p | 仅保留ms中键满足条件谓词p的映射关系 |
ms.clear() | 删除ms中的所有映射关系 |
变换 | |
ms transform f | 以函数f转换ms中所有键值对(译注:原文比较含糊,transform中参数f的类型是(A, B) => B,即对ms中的所有键值对调用f,得到一个新的值,并用该值替换原键值对中的值) |
克隆 | |
ms.clone | 返回一个新的可变映射(Map),其中包含与ms相同的映射关系 |
Synchronized Sets and Maps
无论什么样的Map实现,只需混入SychronizedMap trait,就可以得到对应的线程安全版的Map。例如,我们可以像下述代码那样在HashMap中混入SynchronizedMap。
import scala.collection.mutable.{Map,SynchronizedMap,HashMap}
object MapMaker{
def makeMap: Map[String,String] = {
new HashMap[String,String] with SynchronizedMap[String,String]{ //注意这里的with
override def default(key: String) = "why do you want to know"
}
}
}
当向某个Map查询给定的键所对应的值,而Map中不存在与该键相关联的值时,默认情况下会触发一个NoSuchElementException异常。不过,如果自定义一个Map类并覆写default方法,便可以针对不存在的键返回一个default方法返回的值。
同步集合(synchronized set)的创建方法与同步映射(synchronized map)类似。
import scala.collection.mutable
val synchroSet = new mutable.HashSet[Int] with mutable.SynchronizedSet[Int]
另外,这里加两个例子理解with也就是Class Composition with mixins
abstract class A { val message: String }
class B extends A { val message = "I'm an instance of B"}
trait C extends A { def loudMessage = message.toUpperCase() }
class extends B with C
val d = new D
println(d.message) //I'm an instance of class B
println(d.loudMessage) //I'M AN INSTANCE OF CLASS B
abstract class AbsIterator{
type T
def hasNext: Boolean
def next(): T
}
class StringIterator(s: String) extends AbsIterator{
type T = Char
private var i = 0
def hasNext = i < s.length
def next() = {
val ch = s charAt i
i += 1
ch
}
}
trait RichIterator extends AbsIterator{
def foreach(f: T => Unit): Unit = while(hasNext) f(next())
}
class RichStringIterator extends StringIterator("Scala") with RichIterator
val richStringIter = new RichStringIterator
richStringIter foreach println
//结果
//S
//c
//a
//l
//a
【推荐】国内首个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,是通过提示词来发起调用的吗