Dart 之映射(Map)

262 阅读5分钟

Dart之映射.png

前言

你是否需要将数据以键值对的形式关联,例如快速查询商品信息,或是实现高效的数据索引?在Dart中,Map正是为此而设计的核心数据结构。与ListSet不同,Map通过唯一的键(Key)关联值(Value),既能像字典一样直观检索,又能以接近O(1)的时间复杂度实现快速查找,成为处理复杂数据关系的“神器”。现在就让我们一起来了解一下这把处理复杂数据关系的“神器”怎么使用吧。

一、基本概念

1.1、定义

映射(Map)是无序的键值对集合。包含键和值两个部分,其中键具有唯一性,即不同键可以对应相同的值。

如图所示,每一个键(唯一)都对应一个值(可以重复)。

映射图示.png

1.2、特点

  • 无序:映射中的元素没有按照一定的顺序进行排列。
  • 键具有唯一性
  • 值可以重复

1.3、泛型支持

Dart中映射(Map)和列表(List)集合(Set)一样,不仅支持指定元素为同一类型,也支持元素为不同类型(通过动态类型声明dynamic)。

二、创建和初始化

2.1、直接创建

映射(Map)和集合(Set)一样可通过大括号({})直接创建。

示例:

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'James':54,'Daniel':8,'Sophia':12,'Emma':2};
}

2.2、使用构造函数创建

  • <String,int>{}:创建一个空映射。
  • Map<String,int>.from() 创建。

示例:

void main() {
  Map<String,int> emptyMap = <String,int>{};
  print(emptyMap); // 输出:{}
  Map<String,int> fromMap = Map<String,int>.from({'John':2,'Michael':23,'David':23});
  print(fromMap); // 输出:{John: 2, Michael: 23, David: 23}
}

2.3、使用Map.of创建

映射(Map)和集合(Set)类似都可通过 of() 构造函数进行创建。

示例:

void main() {
  Map<String,int> ofMap = Map.of({'John':2,'Michael':23,'David':23});
  print(ofMap); // 输出:{John: 2, Michael: 23, David: 23}
}

2.4、使用Map.fromIterables和Map.fromEntries创建

  • Map.fromIterables():第一个参数为的可迭代对象,第二个为的可迭代对象。
  • Map.fromEntries():参数为以MapEntry对象为元素的可迭代对象。

示例:

void main() {
  List<String> keyList = ['John','Michael','David'];
  List<int> valueList = [2,23,23];
  Map<String,int> fromIterablesMap = Map.fromIterables(keyList,valueList);
  print(fromIterablesMap); // 输出:{John: 2, Michael: 23, David: 23}
  // 创建MapEntry对象的列表entries。
  List<MapEntry<String,int>> entries = [MapEntry('John', 2),MapEntry('Michael', 23),MapEntry('David', 23)];
  Map<String,int> fromEntriesMap = Map.fromEntries(entries);
  print(fromEntriesMap); // 输出:{John: 2, Michael: 23, David: 23}
}

三、不可变映射

Dart映射(Map)与集合(Set)、列表(List)相同,都支持定义不可修改的对象。映射(Map)使用Map.unmodifiable()构造函数创建。

示例:

void main() {
  Map<String,int> unmodifiableMap = Map.unmodifiable({'John':2,'Michael':23,'David':23});
  print(unmodifiableMap); // 输出:{John: 2, Michael: 23, David: 23}
  // 尝试修改内容
  unmodifiableMap.addAll({'Daniel':8,'Sophia':12,'Emma':2}); 
  // Unsupported operation: Cannot modify unmodifiable map
}

运行时报错:

image.png

四、常用属性和方法

4.1、常用属性

  • length:获取映射的键值对个数。
  • isEmpty:判断映射中是否为空映射。为空则返回true,否则返回false。
  • keys:获取映射中的所有键。
  • values:获取映射中的所有值。
  • entries:获取映射中的所有MapEntry对象。

示例:

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'James':54,'Daniel':8,'Emma':2};
  print(scoresMap.length); // 输出:6
  print(scoresMap.isEmpty); // 输出:false
  print(scoresMap.keys); // 输出:(John, Michael, David, James, Daniel, Emma)
  print(scoresMap.values); // 输出:(2, 23, 23, 54, 8, 2)
  print(scoresMap.entries);
  // 输出:(MapEntry(John: 2), MapEntry(Michael: 23), MapEntry(David: 23), ..., MapEntry(Daniel: 8), MapEntry(Emma: 2))
}

4.2、常用方法

  • containsKey():判断映射键中是否包含某个键。
  • containsValue():判断映射值中是否包含某个值

示例:

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'James':54,'Daniel':8,'Emma':2};
  print(scoresMap.containsKey('John')); // 包含键John 输出:true
  print(scoresMap.containsValue(1200)); // 不包含值1200 输出:false
}

五、访问元素

映射(Map)除了不仅支持遍历,还支持通过键访问键值对的值。

5.1、通过键访问

映射中每个键与每个值一一对应。因此可以通过键来访问值(就像列表中使用下标访问元素)。

示例:

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'James':54,'Daniel':8,'Emma':2};
  print(scoresMap['John']); // 输出:2
}

5.2、遍历

将映射中的元素访问一遍。

  • for-in遍历,结合entries属性。
  • 高阶函数 forEach() 遍历。

示例: for-in遍历

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'James':54,'Daniel':8,'Emma':2};
  for (var entry in scoresMap.entries){
    print('${entry.key} : ${entry.value}');
  }
}

示例: 高阶函数forEach()遍历

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'James':54,'Daniel':8,'Emma':2};
  scoresMap.forEach((key,value) => print('$key : $value'));
}

六、添加元素

  • 可通过键添加键值对。如果添加的键在映射中存在,则将映射中键对应的值进行更新。
  • addAll():批量添加键值对。
  • addEntries():通过MapEntry对象添加键值对。

示例: 通过键添加

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'Emma':2};
  scoresMap['Emma'] = 1200;
  print(scoresMap); // 更新scoresMap中Emma的值 输出:{John: 2, Michael: 23, David: 23, Emma: 1200}
  scoresMap['Daniel'] = 234;
  print(scoresMap); // 输出:{John: 2, Michael: 23, David: 23, Emma: 1200, Daniel: 234}
}

示例: addAll()与addEntries()添加

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'Emma':2};
  scoresMap.addAll({'Daniel': 234});
  print(scoresMap); // 输出:{John: 2, Michael: 23, David: 23, Emma: 1200, Daniel: 234}
  scoresMap.addEntries([MapEntry('Michael',23),MapEntry('Sophia',12)]);
  print(scoresMap); // 输出:{John: 2, Michael: 23, David: 23, Emma: 2, Daniel: 234, Sophia: 12}
}

七、修改元素

通过键访问到元素,再进行修改。

示例:

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'Emma':2};
  scoresMap['John'] = 1200;
  print(scoresMap); // 输出:{John: 1200, Michael: 23, David: 23, Emma: 2}
}

八、移除元素

  • remove():移除某个键值对。
  • removeWhere():移除满足一定条件的键值对。
  • clear():清空映射中键值对。

示例:

void main() {
  Map<String,int> scoresMap = {'John':2,'Michael':23,'David':23,'Emma':2};
  scoresMap.remove('John');
  print(scoresMap); // 输出:{Michael: 23, David: 23, Emma: 2}
  // 移除Michael键值对。
  scoresMap.removeWhere((key,value) => key=='Michael');
  print(scoresMap); // 输出:{David: 23, Emma: 2}
  scoresMap.clear();
  print(scoresMap); // 输出:{}
}

九、总结

本小节归纳总结如下:

属性或方法
创建和初始化1、使用{}直接创建
2、Map<String,int>.from()
3、Map<String,int>.fromIterables()
4、Map<Sring,int>.fromEntries()
5、Map.of()
不可变映射使用Map.unmodifiable()创建
常用属性和方法1、length属性 2、isEmpty属性 3、keys属性
4、values属性 5、Entries属性
1、containsKey()方法 2、containsValue()方法
访问元素1、使用键访问
2、for-in循环遍历(结合Entries属性)
3、高阶函数forEach()遍历
添加元素1、使用键添加
2、addAll()
3、addEntries()
修改元素先访问,再修改
移除元素1、remove()移除键值对
2、removeWhere()移除符合条件的键值对
3、clear()清空映射中所有键值对