dart学习第 3 节:集合类型(上)—— List 与 Set 的使用

90 阅读4分钟

今天我们将学习 Dart 中非常重要的集合类型,这节课先聚焦于 List(列表)  和 Set(集合)  的使用。集合类型可以帮助我们高效地管理和操作多个数据,是开发中不可或缺的工具。

一、List(列表):有序的数据集

List 是 Dart 中最常用的集合类型,它是一个有序的、可重复的数据集合,类似其他语言中的数组。

1. 如何创建 List

创建 List 有多种方式,最常用的有以下几种:

方式一:使用字面量创建(推荐)

void main() {
  // 创建整数列表
  List<int> numbers = [1, 2, 3, 4, 5];

  // 创建字符串列表
  List<String> fruits = ['苹果', '香蕉', '橙子'];

  // 创建混合类型列表(不推荐,建议指定具体类型)
  List<dynamic> mixed = [1, 'hello', true, 3.14];

  print(numbers); // 输出:[1, 2, 3, 4, 5]
  print(fruits); // 输出:[苹果, 香蕉, 橙子]
}

方式二:使用 List 构造函数

void main() {
  // 创建空列表
  List<String> emptyList = List.empty();

  // 创建固定长度的列表(初始化值为 null)
  List<int> fixedList = List.filled(3, 0); // 长度为3,初始值为0
  print(fixedList); // 输出:[0, 0, 0]

  // 创建可增长的列表
  List<String> growableList = List<String>.empty(growable: true);
  growableList.add('dart');
  print(growableList); // 输出:[dart]
}

2. 访问和修改 List 元素

List 中的元素通过索引访问(索引从 0 开始):

void main() {
  List<String> colors = ['红', '绿', '蓝'];

  // 访问元素
  print(colors[0]); // 输出:红
  print(colors[2]); // 输出:蓝

  // 修改元素
  colors[1] = '黄';
  print(colors); // 输出:[红, 黄, 蓝]

  // 获取列表长度
  print(colors.length); // 输出:3
}

3. 添加和删除元素

对于可增长的列表,我们可以动态添加或删除元素:

void main() {
  List<int> nums = [10, 20];

  // 添加单个元素
  nums.add(30);
  print(nums); // 输出:[10, 20, 30]

  // 添加多个元素
  nums.addAll([40, 50]);
  print(nums); // 输出:[10, 20, 30, 40, 50]

  // 在指定位置插入元素
  nums.insert(1, 15); // 在索引1处插入15
  print(nums); // 输出:[10, 15, 20, 30, 40, 50]

  // 删除指定值的元素(只删除第一个匹配项)
  nums.remove(20);
  print(nums); // 输出:[10, 15, 30, 40, 50]

  // 删除指定索引的元素
  nums.removeAt(0);
  print(nums); // 输出:[15, 30, 40, 50]

  // 清空列表
  nums.clear();
  print(nums); // 输出:[]
}

4. 遍历 List

遍历列表是常见操作,最常用的方式是 for-in 循环:

void main() {
  List<String> languages = ['Dart', 'Java', 'Python', 'JavaScript'];

  // 方式一:for-in 循环(推荐)
  for (String lang in languages) {
    print(lang);
  }

  // 方式二:普通 for 循环(需要索引时使用)
  for (int i = 0; i < languages.length; i++) {
    print('索引 $i: ${languages[i]}');
  }

  // 方式三:forEach 方法(函数式编程风格)
  languages.forEach((lang) {
    print('语言:$lang');
  });
}

二、Set(集合):无序的去重数据集

Set 是一个无序的、不可重复的数据集合,适合用于存储不希望有重复元素的数据。

1. 创建 Set

void main() {
  // 方式一:使用字面量(注意用大括号)
  Set<int> numbers = {1, 2, 3, 4};

  // 方式二:使用 Set 构造函数
  Set<String> fruits = Set.from(['苹果', '香蕉', '苹果']); // 自动去重

  print(numbers); // 输出:{1, 2, 3, 4}
  print(fruits); // 输出:{苹果, 香蕉}(重复的"苹果"被去除)

  // 创建空 Set
  Set<String> emptySet1 = {};
  Set<String> emptySet2 = Set<String>(); // 构造函数

  print(emptySet1.isEmpty); // 输出: true
  print(emptySet2.isEmpty); // 输出: true
}

注意:{} 默认创建的是 Set,而不是 Map(后面会学到)。如果要创建空 Map,需要指定类型 Map()

2. Set 的核心特性:去重

当添加重复元素时,Set 会自动忽略:

void main() {
  Set<String> names = {'张三', '李四', '张三'};
  print(names); // 输出:{张三, 李四}

  // 添加重复元素
  names.add('李四');
  print(names); // 输出:{张三, 李四}(无变化)
}

这个特性非常实用,比如需要对数据进行去重处理时:

void main() {
  // 原始列表(有重复元素)
  List<int> rawData = [1, 2, 2, 3, 3, 3, 4];

  // 转换为 Set 实现去重,再转回 List
  List<int> uniqueData = rawData.toSet().toList();

  print(uniqueData); // 输出:[1, 2, 3, 4]
}

3. Set 的交集、并集和差集

Set 提供了方便的集合运算方法:

  • 并集(union) :两个集合中所有的元素(去重)
  • 交集(intersection) :两个集合中共同拥有的元素
  • 差集(difference) :当前集合有而另一个集合没有的元素
void main() {
  Set<int> a = {1, 2, 3, 4};
  Set<int> b = {3, 4, 5, 6};

  // 并集:a 和 b 所有元素
  Set<int> union = a.union(b);
  print(union); // 输出:{1, 2, 3, 4, 5, 6}

  // 交集:a 和 b 共有的元素
  Set<int> intersection = a.intersection(b);
  print(intersection); // 输出:{3, 4}

  // 差集:a 有而 b 没有的元素
  Set<int> difference = a.difference(b);
  print(difference); // 输出:{1, 2}
}

4. Set 的添加和删除操作

Set 的操作与 List 类似,但因为无序,没有索引相关的方法:

void main() {
  Set<String> countries = {'中国', '美国'};

  // 添加元素
  countries.add('日本');
  print(countries); // 输出:{中国, 美国, 日本}(顺序可能不同)

  // 添加多个元素
  countries.addAll(['法国', '德国']);
  print(countries); // 输出:{中国, 美国, 日本, 法国, 德国}

  // 删除元素
  countries.remove('美国');
  print(countries); // 输出:{中国, 日本, 法国, 德国}

  // 清空集合
  countries.clear();
  print(countries); // 输出:{}
}

三、集合的常用方法(map/where/toList 等)

Dart 的集合提供了许多强大的方法,让我们可以更简洁地处理数据,这些方法在 List 和 Set 中都可以使用。

1. map ():转换元素

map() 方法用于将集合中的每个元素按照指定规则转换,返回一个新的可迭代对象:

void main() {
  List<int> numbers = [1, 2, 3, 4];

  // 将每个数字乘以 2
  var doubled = numbers.map((n) => n * 2);

  // map() 返回的是 Iterable,通常转换为 List
  List<int> doubledList = doubled.toList();

  print(doubledList); // 输出:[2, 4, 6, 8]

  // 字符串处理示例
  List<String> names = ['张三', '李四', '王五'];
  List<String> greetings = names.map((name) => '你好,$name!').toList();
  print(greetings); // 输出:[你好,张三!, 你好,李四!, 你好,王五!]
}

2. where ():筛选元素

where() 方法用于根据条件筛选元素,返回符合条件的元素组成的可迭代对象:

void main() {
  List<int> ages = [12, 18, 20, 15, 25, 30];

  // 筛选出成年人(年龄 >= 18)
  var adults = ages.where((age) => age >= 18);

  List<int> adultList = adults.toList();
  print(adultList); // 输出:[18, 20, 25, 30]

  // Set 筛选示例
  Set<double> prices = {19.9, 29.9, 9.9, 39.9, 5.9};
  List<double> cheapPrices = prices.where((p) => p < 20).toList();
  print(cheapPrices); // 输出:[19.9, 9.9, 5.9]
}

3. toList () 和 toSet ():类型转换

这两个方法用于在 List 和 Set 之间进行转换:

void main() {
  Set<String> set = {'a', 'b', 'c'};
  List<String> list = set.toList(); // Set 转 List
  print(list); // 输出:[a, b, c](顺序可能不同)

  List<String> duplicateList = ['a', 'a', 'b'];
  Set<String> uniqueSet = duplicateList.toSet(); // List 转 Set(去重)
  print(uniqueSet); // 输出:{a, b}
}

4. contains ():检查元素是否存在

void main() {
  List<String> fruits = ['苹果', '香蕉', '橙子'];
  print(fruits.contains('香蕉')); // 输出:true
  print(fruits.contains('西瓜')); // 输出:false

  Set<int> nums = {1, 3, 5};
  print(nums.contains(3)); // 输出:true
}

5. any () 和 every ():判断条件

  • any():只要有一个元素满足条件就返回 true
  • every():所有元素都满足条件才返回 true
void main() {
  List<int> scores = [85, 92, 78, 60];

  // 是否有不及格的分数(<60)
  bool hasFailed = scores.any((s) => s < 60);
  print(hasFailed); // 输出:false(所有都 >=60)

  // 是否所有分数都及格
  bool allPassed = scores.every((s) => s >= 60);
  print(allPassed); // 输出:true
}

四、List 与 Set 的区别与选用场景

特性ListSet
顺序有序(保留插入顺序)无序(Dart 3.0+ 部分有序)
重复性允许重复元素不允许重复元素
索引访问支持(通过索引访问)不支持(无索引)
查找效率随元素增多而降低始终较高(哈希表实现)

选用建议

  • 当需要保持元素顺序或允许重复时,使用 List
  • 当需要去重或高效判断元素是否存在时,使用 Set
  • 当需要频繁进行集合运算(交集、并集等)时,使用 Set