Scala 集合:Map API
Map 定义了键值对的特质类型,区分可变与不可变,间接继承了偏函数 PartialFunction 特质,所以一个 Map 本质上也是一个偏函数,其定义如下:
1 | trait Map[K, +V] extends Iterable[(K, V)] with GenMap[K, V] with MapLike[K, V, Map[K, V]] |
其伴生对象提供了构造 Map 对象的简单方式,示例:
1 | val map1 = Map("name" -> "zhenchao", "age" -> 28) |
可变 Map 与不可变 Map 的相互转换:
- 可变 -> 不可变
将可变 Map 转换成不可变 Map 的最简单方式就是调用 toMap 函数,但是如果希望转换成特定类型的不可变 Map 类型,则需要借助 ++
函数,示例:
1 | val mmap = mutable.Map("name" -> "zhenchao", "age" -> 28) |
- 不可变 -> 可变
不可变 Map 转换成可变 Map 也需要借助 ++
函数实现,示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
一. 查询操作
1.1 get & getOrElse & apply
函数 get、getOrElse 和 apply 均用于从 Map 对象中获取元素,区别在于 get 操作返回 Option 类型,getOrElse 允许在对应 key 不命中时返回默认的 value,而 apply 同样是返回指定的 key 对应的 value,但是在 key 不命中时默认抛出 NoSuchElementException 异常。示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
函数 apply 同样可以使用 ()
表达式简写。
1.2 withDefault & withDefaultValue
上面在使用 apply 函数时,在 key 不命中的情况下默认会抛出 NoSuchElementException,如果希望改变这种行为,我们可以使用 withDefault 或 withDefaultValue 函数自定义默认行为,其中 withDefault 接收一个函数(入参是 key),而 withDefaultValue 则接收一个默认值。示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
1.3 getOrElseUpdate
对于可变集合来说,可以使用 getOrElseUpdate 函数(定义如下),该函数允许提供一个 op 操作,如果对应的 key 存在则返回对应的 value,否则会计算 op 得到一个 value,并更新 Map 对象,同时返回该 value。
1 | def getOrElseUpdate(key: K, op: => V): V |
示例:
1 | val mmap = mutable.Map("name" -> "zhenchao", "age" -> 28) |
二. 插入操作
插入操作允许 value 为 null,但不允许 key 为 null,此外对于已经存在的 key,插入操作相当于更新操作。
2.1 +
函数 +
用于往 Map 对象中添加一个或多个键值对,函数定义如下:
1 | def + [V1 >: V](kv: (K, V1)): Map[K, V1] |
示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
2.2 ++ & ++:
函数 ++
接收一个 GenTraversableOnce 类型的参数,只要是继承 GenTraversableOnce 的集合都可以作为参数,函数会将参数中所包含的元素添加到原 Map 对象中,并创建一个新的 Map 返回。示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
函数 ++:
是 ++
的右结合版本。
2.3 += & ++= & put
对于可变集合而言,可以实现原地插入,函数 +=
对标 +
,函数 ++=
对标 ++
,函数 put 用于插入单个键值对,并返回一个 Option 类型,表示插入操作之前对应的 value。示例:
1 | val mmap = mutable.Map("name" -> "zhenchao", "age" -> 28) |
三. 更新操作
3.1 updated
函数 updated 用于更新 Map 对象中指定的 key 和 value,如果不存在则添加,示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
3.2 update & put
对于可变集合而言,可以实现原地更新操作,函数 update 用于更新一个可变 Map 中的 key 和 value,如果不存在则会添加,效果上等价于 put,示例:
1 | val mmap = mutable.Map("name" -> "zhenchao", "age" -> 28) |
函数 update 同样可以简写为 ()
表达式。
四. 删除操作
4.1 - & --
函数 -
用于删除指定的一个或多个 key,而函数 --
则接收一个 GenTraversableOnce 类型参数,用于批量删除给定集合中包含的所有 key,示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
4.2 -= & --= & remove & clear
对于可变集合而言,可以实现原地删除,函数 -=
对标 -
,函数 --=
对标 --
,示例:
1 | val mmap = mutable.Map("name" -> "zhenchao", "age" -> 28) |
函数 remove 用于从可变 Map 对象中删除给定的 key,并返回 key 对应的 value,Option 类型。函数 clear 用于清空整个 Map 对象。
五. 包含检查
5.1 contains & isDefinedAt
函数 contains 和 isDefinedAt 均用于检查 Map 对象中是否包含指定的 key,示例:
1 | val map = Map("name" -> "zhenchao", "age" -> 28) |
其中 isDefinedAt 继承自偏函数。
六. 获取键或值的集合
6.1 keys & keySet & keysIterator
函数 keys、keySet 和 keysIterator 均用于获取 Map 对象键的集合,区别在于函数 keys 返回的是 Iterable[K]
类型对象;函数 keySet 返回的是 Set[K]
类型对象;而函数 keysIterator 返回一个 Iterator[K]
类型对象。
6.2 values & valuesIterator
函数 values 和 valuesIterator 均用于获取 Map 对象值的集合,区别在于函数 values 返回的是 Iterable[V]
类型,而函数 valuesIterator 返回的是 Iterator[V]
类型。
七. 转换操作
Map 对象考虑其特性,增加了 filterKeys、mapValues 和 transform 函数。
7.1 filterKeys
函数 filterKeys 对 Map 对象中的 key 进行筛选,并保留满足条件的元素,示例:
1 | val map = Map(1 -> "zhangsan", 2 -> "lisi", 3 -> "wanger") |
7.2 mapValues & transform
函数 mapValues 和 transform 均用于对 Map 对象的值进行转换,区别在于函数 mapValues 的入参只有 value,而 transform 的入参除了 value,还包含 key,示例:
1 | val map = Map(1 -> "zhangsan", 2 -> "lisi", 3 -> "wanger") |
对于可变 Map 而言,因为是原地转换,所以要求 transform 操作输出的 value 类型与输入的类型相同。
八. 反转操作
对于给定的 Map 集合,我们可以使用 map 函数很容易将 key 和 value 反转,但是如果 value 存在重复,那么这个时候我们可能希望反转之后的 value 是一个集合类型,这种需求该如何实现?
1 | // value 不重复 |
上述示例中重复 value 的反转执行流程如下:
- 对包含重复 value 的 Map 执行 groupBy 操作:
Map(2 -> Map(b -> 2, c -> 2), 1 -> Map(e -> 1, a -> 1), 3 -> Map(d -> 3))
; - 对步骤 1 的结果执行 mapValues 操作,提取 key,并封装成 List 集合。