Dart 基础 – 内置类型 – Map 集合
版权归作者 ©刘龙宾 所有,本文章未经作者允许,禁止私自转载!
Map 是一个无序的 key-value
(键值对)集合,就是大家熟知的 dictionary 或者 hash。 Map 将 kay 与 value 关联,以便于检索。
通常来说,Map 是用来关联 keys
和 values
的对象。其中键和值都可以是任何类型的对象。每个键只能出现一次,但是值可以重复出现多次。
1. 创建 Map 集合
1.1 基于字面量创建 Map
1.1.1 强类型的 Map
声明强类型 Map 的语法格式为 <keyType, valueType>{}
,示例代码如下:
void main(List<String> args) {
// 1. 创建空的 Map 集合
// 键是字符串,值是字符串的数组
var hobbies1 = <String, List<String>>{};
// 输出 true,证明 hobbies1 是空 Map
print(hobbies1.isEmpty);
// 2. 创建非空的 Map 集合
// 键是字符串,值是字符串的数组
var hobbies2 = <String, List<String>>{
'liulongbin': ['games', 'coding', 'music'],
'escook': ['eat', 'sleep', 'run']
};
// 输出 2,证明 hobbies2 中包含两个键值对
print(hobbies2.length);
}
1.1.2 弱类型的 Map
直接使用 {}
字面量定义的就是弱类型的 Map,它的完整写法是 <dynamic, dynamic>{}
。弱类型 Map 的好处是可以向 Map 集合中添加任意类型的键值对。示例代码如下:
void main(List<String> args) {
// 1. 声明键和值都为 dynamic 类型的 Map,
// 完整写法是 var maps = <dynamic, dynamic>{};
var maps = {};
// 2. 向 Map 中添加键值对
// 键是 String,值是 List<String>
maps['liulongbin'] = ['games', 'coding', 'music'];
// 键是 int,值是 String
maps[1] = 'hello';
// 键是 int,值是 String
maps[2] = 'world';
// 3. 输出 {liulongbin: [games, coding, music], 1: hello, 2: world}
print(maps);
}
1.1.3 弱类型的键或弱类型的值
在使用 Map 时,还可以单独指定弱类型的键,或单独指定弱类型的值,示例代码如下:
void main(List<String> args) {
// 1. 定义弱类型的键,强类型的值
var map1 = <dynamic, String>{};
// 2. 定义强类型的键,弱类型的值
var map2 = <int, dynamic>{};
// 1.1 向 map1 中添加三个键值对
map1[0] = 'red';
map1[true] = 'blue';
map1['flag'] = 'green';
// 1.2 输出 {0: red, true: blue, flag: green}
print(map1);
// 2.1 向 map2 中添加四个键值对
map2[0] = 'red';
map2[1] = false;
map2[2] = 999;
map2[3] = <String>['A', 'B', 'C'];
// 2.2 输出 {0: red, 1: false, 2: 999, 3: [A, B, C]}
print(map2);
}
1.2 基于构造函数创建 Map
基于 Map()
构造函数同样可以创建弱类型和强类型的 Map,示例代码如下:
void main(List<String> args) {
// 1. 创建弱类型的空 Map
var map1 = Map();
// 2. 创建强类型的空 Map
var map2 = Map<int, String>();
}
2. 操作 Map 元素
2.1 添加元素
2.1.1 直接使用 [] 添加元素
向 Map 集合中添加元素最常用的方式是 []
,示例代码如下:
void main(List<String> args) {
// 1. 定义空 Map
var names = <int, String>{};
// 2. 添加元素
names[0] = 'liulongbin';
// 3. 输出 {0: liulongbin}
print(names);
}
2.1.2 addAll
还可以调用 addAll
方法,把指定 Map 中的元素添加到当前 Map 中,示例代码如下:
void main(List<String> args) {
// 1. 定义两个 Map
var names = <int, String>{0: 'liulongbin', 1: 'escook'};
var others = <int, String>{1: 'zs', 2: 'ls', 3: 'xyz'};
// 2. 把 others 中的键值对添加到 names 中
// names 和 others 重复的键,会被 others 中对应的值覆盖
names.addAll(others);
// 3. 输出 {0: liulongbin, 1: zs, 2: ls, 3: xyz}
print(names);
}
2.2 修改元素
2.2.1 直接使用 [] 修改
修改元素的值,最简单的方式就是利用 []
为指定的键重新赋值,示例代码如下:
void main(List<String> args) {
var names = <String, int>{'liulongbin': 18};
// 输出 {liulongbin: 18}
print(names);
// 使用 [] 为指定的 key 重新赋值
names['liulongbin'] = 20;
// 输出 {liulongbin: 20}
print(names);
}
2.2.2 update
调用 Map 对象的 update
方法,可以更新指定 key 的值,示例代码如下:
void main(List<String> args) {
// 1. 定义 Map 对象
var names = <String, int>{'liulongbin': 18};
// 2. 调用 update 方法,
// 参数1:要更新的 key
// 参数2:匿名函数,形参 value 是 key 当前对应的值,函数必须返回一个值当作 key 的新值
// 返回值:更新后的新值
var result = names.update('liulongbin', (value) => value + 1);
// 3. 输出 {liulongbin: 19}
print(names);
// 4. 输出 19
print(result);
}
同时 update
函数还接收第三个参数 ifAbsent
,它是一个匿名函数,用来提供一个缺省的候补值。如果在更新属性值的时候发现 Map 中不包含当前 key,则为当前 Map 新增 key 属性,属性值就是这个候补值。示例代码如下:
void main(List<String> args) {
// 1. 定义 Map 对象
var names = <String, int>{'liulongbin': 18};
// 2. 调用 update 方法,
// 参数1:要更新的 key
// 参数2:匿名函数,形参 value 是 key 当前对应的值,函数必须返回一个值当作 key 的新值
// 参数3:候补值,如果 key 不存在,则为 Map 新增 key 属性,属性值是当前的候补值
// 返回值:更新后的新值
var result = names.update('escook', (value) => value + 1, ifAbsent: () => 0);
// 3. 输出 {liulongbin: 18, escook: 0}
// 由于 names 对象中原本不包含 escook 属性,
// 所以 update 方法为 names 新增了 escook 属性,属性值为参数3提供的候补值
print(names);
// 4. 输出 0
print(result);
}
2.2.3 updateAll
updateAll
可以批量更新 Map 中的每个值,示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{'liulongbin': 'A', 'escook': 'D'};
// 2. 在每个属性值的后面添加 + 后缀
scores.updateAll((key, value) => '$value+');
// 3. 输出 {liulongbin: A+, escook: D+}
print(scores);
}
2.3 删除元素
2.3.1 remove
remove
方法根据 key 从 Map 中移除键值对,并返回移除的 value 值。如果移除的 key 不存在,则返回 null
。示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{'liulongbin': 'A', 'escook': 'D'};
// 2. 移除 escook 键以及对应的值
var result = scores.remove('escook');
// 3.1 输出 D
print(result);
// 3.2 输出 {liulongbin: A}
print(scores);
// ----
// 4. 移除不存在的属性 abc
var result2 = scores.remove('abc');
// 5. 输出 null
print(result2);
}
2.3.2 removeWhere
removeWhere
可以根据给定的条件,移除符合条件的元素,示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{
'liulongbin': 'A',
'escook': 'D',
'zs': 'C',
'ls': 'D'
};
// 2. 移除分数为 D 的元素,或 key 为 'zs' 的元素
scores.removeWhere((key, value) => value == 'D' || key == 'zs');
// 3. 输出 {liulongbin: A}
print(scores);
}
2.4 清空元素
clear
方法可以清空 Map 集合,示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{'liulongbin': 'A', 'escook': 'D'};
// 2. 清空所有键值对
scores.clear();
// 3. 输出 true,证明 scores 已为空
print(scores.isEmpty);
}
3. Map 常用方法
3.1 containsKey
containsKey
用来判断 Map 中是否包含指定的 key,如果包含则返回 true,如果不包含则返回 false。示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{
'liulongbin': 'A',
'escook': 'D',
'zs': 'C',
'ls': 'D'
};
var res1 = scores.containsKey('escook');
print(res1); // 输出 true
var res2 = scores.containsKey('nbb');
print(res2); // 输出 false
}
3.2 containsValue
containsValue
用来判断 Map 中是否包含指定的 value,如果包含则返回 true,如果不包含则返回 false。示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{
'liulongbin': 'A',
'escook': 'D',
'zs': 'C',
'ls': 'D'
};
var res1 = scores.containsValue('A');
print(res1); // 输出 true
var res2 = scores.containsValue('B');
print(res2); // 输出 false
}
3.3 putIfAbsent
putIfAbsent
方法会为对象添加原本不存在的属性,并为其赋值。如果要添加的属性已存在,则不会覆盖,仅把此属性的原值返回。示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{'liulongbin': 'A', 'escook': 'D'};
// 2. 检测到 scores 中已包含 escook 属性,
// 因此不会重新设置 escook 属性的值,只是单纯的把原属性值 'D' 返回给变量 result
var result = scores.putIfAbsent('escook', () => 'C');
// 3.1 输出 {liulongbin: A, escook: D},没有任何变化
print(scores);
// 3.2 输出 D,原值
print(result);
// ----
// 4. 检测到 scores 中不包含 llb 属性,
// 因此会给 scores 对象添加新属性 llb,属性值为字符串 A+
var result2 = scores.putIfAbsent('llb', () => 'A+');
// 5.1 输出 {liulongbin: A, escook: D, llb: A+}
print(scores);
// 5.2 输出 A+
print(result2);
}
注意:如果您想覆盖原属性值或添加原本没有的新属性,建议使用
update
方法或使用[]
的方式。
3.4 forEach
forEach
方法可以遍历当前 Map 对象中的每个键值对,并对他们进行自定义的操作。示例代码如下:
void main(List<String> args) {
// 1. 定义 Map
var scores = <String, String>{'liulongbin': 'A', 'escook': 'D'};
// 2. 遍历 scores 中的每个键值对
scores.forEach((key, value) {
print('学生 $key 的成绩为 $value');
});
}
注意:List 数组、Set 集合、Map 都支持 forEach 方法对象集合中的元素进行遍历操作,而且用法相同。
Map 可以像 List 一样支持使用扩展操作符(...
和 ...?
)以及集合的 if
和 for
操作。关于 Map
集合的更多操作,请参考 Map 的官方文档
版权归作者 ©刘龙宾 所有,本文章未经作者允许,禁止私自转载!。