前言
集合 —— 操作批量数据的核心工具
在 Dart中,Set 是一种特殊的集合类型,它确保每个元素都是唯一的,不允许重复。就像一个精心整理的工具箱,每种工具只出现一次,方便快速查找和使用。Set 适用于需要去重、检查成员资格或进行数学集合操作(如并集、交集)的场景。通过 Set,可以高效地管理和操作不重复的数据项,为应用程序带来简洁性和高性能。
操千曲而后晓声,观千剑而后识器。虐它千百遍方能通晓其真意。
一、基本概念
1.1、图像表示
| 姓名 | 参加的活动 |
|---|---|
| Alice | 短跑100米 |
| Bob | 短跑200米 |
| Charlie | 长跑5000米 |
如上图所示,有一个班级的学生名册,确保每个学生的名字只出现一次,不论他们参加了多少个活动。这就是 Set 的工作方式 —— 它是一个无序且不允许重复元素的集合。
1.2、定义
Set 是一个无序且不允许重复元素的集合。它类似于数学中的集合概念,提供了一种方便的方式来处理唯一的数据项。
// 创建一个 Set 班级学生名册
Set<String> studentRoster = {'Alice', 'Bob', 'Charlie'};
1.3、特点
- 1、无序:就像名册中的名字,不能保证每次读取的顺序。
- 2、不允许重复:每个学生的名字只能出现
一次。
// 尝试添加重复的名字
studentRoster.add('Alice'); // 不会添加,因为已经存在
// 输出名册
print(studentRoster); // 输出: {Alice, Bob, Charlie}
1.4、泛型支持
Dart 的 Set 支持泛型,允许指定列表中元素的具体类型,从而提高代码的类型安全性和可读性。
// 创建一个泛型为int类型的Set
Set<int> numbers = {1, 2, 3, 4, 5};
// 创建一个泛型为String类型的list
Set<String> names = {'Alice', 'Bob', 'Charlie'};
// 创建一个泛型为dynamic类型的list
Set<dynamic> list = {'Alice', 1, false};
二、创建和初始化
2.1、直接创建
最简单的方式是直接在花括号{}中列出元素。
Set<int> numbers = {1, 2, 3, 4, 5};
2.2、使用构造函数
使用 Set 类的构造函数来创建一个空集合或具有初始元素的集合。
// 创建一个空集合
Set<String> emptySet = <String>{};
// 创建一个包含初始元素的集合
Set<int> initialNumbers = Set<int>.from([1, 2, 3, 4, 5]);
2.3、 使用 Set.of 构造函数
Set.of 可以从任何可迭代对象(如 List)创建一个 Set。
Set<int> fromList = Set.of([1, 2, 3, 4, 5]);
三、访问和修改
3.1、访问元素
由于 Set 本身是无序的,它并不支持通过索引访问元素(如 List 那样)。然而,Dart 提供了多种方式来访问 Set 中的元素,主要包括遍历和查找特定元素。下面对应的目录中会有介绍,在此不做过多叙述。
3.2、修改元素
由于 Set 的特性,直接修改某个特定元素并不是像 List 那样简单,因为 Set 不支持通过索引访问和修改元素。可以通过以下几种方法来实现对 Set 中元素的“修改”。
- 1、移除旧元素并添加新元素:
void main() {
Set<String> colors = {'红色', '蓝色', '绿色'};
// 修改 "红色" 为 "粉红色"
if (colors.remove('红色')) {
colors.add('粉红色');
}
print(colors); // 输出: {蓝色, 绿色, 粉红色}
}
- 2、使用
map方法创建新的Set:可以使用map方法将每个元素映射到新值,然后将结果转换回Set。
void main() {
Set<int> numbers = {1, 2, 3, 4, 5};
// 将所有数字加 10
Set<int> updatedNumbers = numbers.map((number) => number + 10).toSet();
print(updatedNumbers); // 输出: {11, 12, 13, 14, 15}
}
- 3、批量修改(使用
removeWhere和addAll)
void main() {
Set<String> fruits = {'苹果', '香蕉', '橙子'};
// 移除以 "苹" 开头的水果,并添加 "草莓"
fruits.removeWhere((fruit) => fruit.startsWith('苹'));
fruits.add('草莓');
print(fruits); // 输出: {香蕉, 橙子, 草莓}
}
3.3、添加元素
使用 add或addAll方法向 Set 中添加新元素。如果元素已经存在,则不会添加。
numbers.add(6);
print(numbers); // 输出: {1, 2, 3, 4, 5, 6
// 使用addAll批量添加元素
numbers.addAll({7, 8, 9});
print(numbers); // 输出: {1, 2, 3, 4, 5, 6, 7, 8, 9}
3.4、移除元素
- 1、移除指定元素:使用
remove方法。
numbers.remove(5);
print(numbers); // 输出: {1, 2, 3, 4, 6, 7, 8, 9}
- 2、清空集合:使用
clear方法。
numbers.clear();
print(numbers); // 输出: {}
四、遍历
4.1、使用for循环
如果确实需要按顺序访问元素,可以先将 Set 转换为 List,然后通过索引访问。
Set<String> colors = {'红色', '蓝色', '绿色'};
List<String> colorList = colors.toList();
for (int i = 0; i < colorList.length; i++) {
print('颜色 ${i + 1}: ${colorList[i]}');
}
注意:由于 Set 是无序的,转换后的 List 可能不会保持原来的插入顺序。
4.2、使用forEach
forEach 方法允许为 Set 中的每个元素执行一个回调函数。
Set<String> colors = {'红色', '蓝色', '绿色'};
colors.forEach((color) => print(color));
4.3、使用for-in循环
for-in 循环提供了一种简洁的方式遍历 Set 中的每个元素。
Set<int> numbers = {1, 2, 3, 4, 5};
for (var number in numbers) {
print(number);
}
五、常用属性和方法
5.1、属性
// length:获取 Set 的大小(元素数量)
print(numbers.length); // 输出: 5
// isEmpty 和 isNotEmpty:检查 Set 是否为空。
print(emptySet.isEmpty); // 输出: true
5.2、常用方法
-
1、查找特定元素:
- 使用
contains方法检查某个元素是否存在于Set中。
print(numbers.contains(5)); // 输出: true- 可以结合
where方法与first、last或single来查找符合条件的第一个或最后一个元素,或者唯一符合条件的元素。
void main() { Set<int> numbers = {1, 2, 3, 4, 5}; // 查找第一个大于 3 的元素 int firstGreaterThanThree = numbers.where((number) => number > 3).first; print('第一个大于 3 的数字是: $firstGreaterThanThree'); // 查找唯一等于 4 的元素 int onlyFour = numbers.singleWhere((number) => number == 4, orElse: () => -1); print('唯一的数字 4 是: $onlyFour'); }- 使用
any和every方法。
void main() { Set<int> numbers = {1, 2, 3, 4, 5}; bool hasEvenNumber = numbers.any((number) => number % 2 == 0); print('Set 中是否有偶数: $hasEvenNumber'); bool allPositive = numbers.every((number) => number > 0); print('所有数字是否都是正数: $allPositive'); } - 使用
-
2、集合操作:
- 并集:使用
union方法计算两个Set的并集。
Set<int> setA = {1, 2, 3}; Set<int> setB = {3, 4, 5}; Set<int> unionSet = setA.union(setB); print(unionSet); // 输出: {1, 2, 3, 4, 5}- 交集:使用
intersection方法计算两个Set的交集。
Set<int> intersectionSet = setA.intersection(setB); print(intersectionSet); // 输出: {3}- 差集:使用
difference方法计算两个Set的差集。
Set<int> differenceSet = setA.difference(setB); print(differenceSet); // 输出: {1, 2} - 并集:使用
六、不可变Set(Set.unmodifiable)
有时需要确保一个 Set 不会被修改。可以使用 Set.unmodifiable 来创建一个不可变的 Set。
Set<int> immutableNumbers = Set.unmodifiable({1, 2, 3, 4, 5});
// 下面这行代码会抛出异常,因为 immutableNumbers 是不可变的
// immutableNumbers.add(6);
七、总结
Set 提供了一种强大而灵活的方式来处理唯一的数据项。通过合理利用 Set 的特性,可以编写出更加简洁、高效和易于维护的代码。
欢迎一键四连(
关注+点赞+收藏+评论)