List(列表)

数组(array)是一组有序的对象(元素)的集合,意味着可以通过下标(从 0 开始的整数)访问数组内对应位置的元素。Dart 的数组即 List,在之前的章节已经多次出现过。

List 有各种不同类型的实现子类,最常见的两类是:

  • 固定长度的(Fixed-length) List:当执行可能改变 List 长度的操作时将引发错误
  • 可增长的(growable) List

List 具有丰富的 API:

  • 操作符 []=, addaddAll 向 List 添加数据。
  • indexOflastIndexOf 检查元素是否在 List 中及其对应位置。
  • remove, removeAt, removeLast, removeRangeremoveWhere 从 List 中移除元素。
  • insertinsertAll向将元素插入到 List 的指定位置。
  • fillRange, replaceRangesetRange 替换 List 某区间内的元素。
  • sort 对 List 中的元素进行排序。
  • shuffle 将 List 中的元素随机打乱。
  • firstWhere 查找满足条件的首个元素,可以指定一个查找失败时的默认值,类似地还有 lastWheresingleWhere 方法。

List 基础

先来看一个简单的示例。

// ex631.dart
void main() {
  var numbers = [1, 2, 3]; // 1 List<int>
  print(numbers); // 2 Output: [1, 2, 3]
  assert(1 == numbers[0]); // 3
  numbers[1] = 9; // 4
  print(numbers); // 5 Output: [1, 9, 3]
  print(numbers.length); // 6 Output: 3
  print(numbers[3]); // 7
  // Unhandled exception:
  // RangeError (length): Invalid value: Not in inclusive range 0..2: 3
}
  1. 使用字面量创建一个 List,其元素放在一对中括号([])内,并以逗号(,)分割;numbers是一个List<int>
  2. 打印numbers
  3. 通过索引(index,从 0 开始的整数,也称为下标)获取对应的元素,numbers[0]返回numbers的第 1 个元素。
  4. numbers 的第 2 个元素修改为9
  5. 再次打印numbers
  6. 打印numbers的长度(元素个数),结果为 3;
  7. 尝试打印numbers的第 4 个元素,遭遇RangeError,因为下标的最大值为 2(长度-1)。

常用构造函数

Dart 的 List 有多个实用的构造函数,现举例说明。

// ex632.dart
void main() {
  final empty = List<int>.empty(growable: true); // 1
  print(empty); // Output: []

  final squares = List.generate(
    10,
    (index) => index * index,
    growable: true,
  ); // 2
  print(squares); // Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

  final zeros = List.filled(5, 0, growable: false); // 3
  print(zeros); // Output: [0, 0, 0, 0, 0]

  final copy = List.of([3, 2, 1]); // 4
  print(copy); // Output: [3, 2, 1]
}
  1. List.empty 创建一个空的 List,命名参数growable用于指定创建的 List 是否可以增长,其默认值为false,表示创建一个固定长度(此处为 0)的 List;
  2. List.generate 的第一个参数指定待创建 List 的初始长度;第二个参数是一个函数(称为generator),其签名为E Function(int index)EList 的类型参数);
  3. List.filled使用指定的数据填充 List,其第一个参数为初始长度,第二个参数乃用于填充的数据;
  4. List.of从一个Iterable对象创建 List。

常用方法

如下示例展示了 List 的一些常用方法或属性以及对应说明。

// ex637.dart
void main() {
  var numbers = [for (var n = 0; n < 5; n++) n * n]; // 1
  print(numbers.runtimeType); // 1a Output: List<int>
  print(numbers.length); // 2 Output: 5
  print(numbers.first); // 3 Output: 0
  print(numbers[0]); // 3a Output: 0
  print(numbers.last); // 4 Output: 16
  print(numbers.isEmpty); // 5 Output: false
  print(numbers.isNotEmpty); // 6 Output: true

  print('-' * 9);
  print(numbers.sublist(1, 3)); // 7 Output: [1, 4]
  print(numbers.getRange(1, 3)); // 8 Output: (1, 4)
  print(numbers.reversed); // 9 Output: (16, 9, 4, 1, 0)
  print(numbers.followedBy([50, 60])); // 10 Output: (0, 1, 4, 9, 16, 50, 60)
  print(numbers.asMap()); // 11 Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

  print('+' * 9);
  print(numbers.where((a) => a % 2 == 0)); // 12 Output: (0, 4, 16)
  print(numbers.whereType<int>()); // 13 Output: (0, 1, 4, 9, 16)

  print(
    numbers.firstWhere((n) => n > 0 && n % 3 == 0, orElse: () => -1),
  ); // 14 Output: 9

  try {
    print(numbers.singleWhere((n) => n % 3 == 0, orElse: () => -1)); // 15
  } on StateError catch (e) {
    print(e.message); // 15a Output: Too many elements
  }

  print(numbers.map((n) => n + 1)); // 16 Output: (1, 2, 5, 10, 17)
  var result = numbers.fold<int>(5, (value, n) => value + n);
  print(result); // 17 Output: 35
  result = numbers.reduce((value, n) => value + n);
  print(result); // 18 Output: 30

  print('*' * 9);
  print(numbers.any((n) => n > 10)); // 19 Output: true
  print(numbers.every((n) => n > 0)); // 20 Output: false
  print(numbers.take(3)); // 21 Output: (0, 1, 4)
  print(numbers.takeWhile((n) => n % 2 == 1)); // 22 Output: ()
  print(numbers.skip(2)); // 23 Output: (4, 9, 16)
  print(numbers.skipWhile((n) => n % 2 == 1)); // 24 Output: (0, 1, 4, 9, 16)

  print('/' * 9);
  numbers.add(20); // 25
  numbers.addAll([30]); // 26
  numbers.removeAt(0); // 27
  numbers.insert(0, 1); // 28
  print(numbers); // 28a Output: [1, 1, 4, 9, 16, 20, 30]
  numbers.replaceRange(1, 3, [10, 40]); // 29
  print(numbers); // 29a Output: [1, 10, 40, 9, 16, 20, 30]
  numbers.shuffle(); // 30
  print(numbers); // 30a
  numbers.sort((a, b) => a - b); // 31
  print(numbers); // 31a Output: [1, 9, 10, 16, 20, 30, 40]
  numbers.clear(); // 32
  print(numbers.isEmpty); // 32a Output: true
}
  1. 构造一个名为 numbers 的 List,其值为 [0, 1, 4, 9, 16]
  2. length 返回 List 中元素的个数(即 List 的长度);
  3. first 返回 List 的第一个元素(element),如果 List 为空将引发StateError;另外可以通过下标 0 访问首个元素;
  4. last返回 List 的最后一个元素,如果 List 为空将引发StateError
  5. isEmpty 检查 List 是否为空;
  6. isNotEmpty 检查 List 是否非空;
  7. sublist(int start, [int? end]) 返回一个新的 List,它包含了原 List 指定区间([start, end),不含end)内的元素;
  8. getRange(int start, int end)sublist(start, end)类似,只不过它返回的是一个Iterable对象;
  9. reversed返回 List 的逆序的Iterable对象;
  10. followedBy(Iterable<E> other)返回一个 Iterable<E> 对象,它包含了该 List 和 other(追加部分)的所有元素;
  11. asMap()返回 List 的 Map 视图;
  12. where(bool test(E element))返回一个Iterable<E>对象,它使用一个test函数来过滤 List 的元素(e),通过测试(test(e)返回true)的那些元素将出现结果集中;
  13. whereType<T>()返回一个Iterable<T>对象,它筛选指定数据类型(T)的元素;
  14. firstWhere(bool test(E element), {E orElse()?})返回首个满足特定条件的元素,如果在 List 中找不到这样的元素,它就调用orElse函数并返回其值(如果 orElse!=null,否则将抛出StateError);
  15. singleWherefirstWhere类似,只不过当有多个元素满足测试条件时会抛出StateError
  16. map<T>(T toElement(E e))返回一个Iterable<T>对象,它使用toElement函数将 List 里的每个元素转换成另一个值;
  17. fold<T>(T initialValue, T combine(T previousValue, E element))遍历 List 并使用combine函数合并元素,最后返回一个单一的值,initialValue用于指定初始值;
  18. reduce(E combine(E value, E element))可被视为fold的特例,它使用 List 的首个元素作为initialValue,然后合并剩余的元素,因而reduce要求 List 非空,在空 List 上调用reduce方法将引起StateError;另外reduce的返回类型为E,而fold的返回类型为T(方法的类型参数);
  19. any(bool test(E element))检查 List 是否包含满足特定条件的元素;
  20. every(bool test(E element))检查是否 List 的每个元素都满足特定条件;
  21. take(int n)获取 List 的前n个元素;
  22. takeWhile(bool test(E value))返回 List 前面的元素(e),直到test(e)false
  23. skip(int n)跳过 List 的前n个元素并返回剩余部分;
  24. skipWhile(bool test(E value))跳过 List 前面的元素(e),直到test(e)false,并返回剩余部分;
  25. add(E value)向 List 中追加一个新元素(添加到末尾);
  26. addAll(Iterable<E> iterable)iterable里的所有元素追加到 List;
  27. removeAt(int index)将对应下标(index)的元素从 List 中移除;
  28. insert(int index, E e)将元素e插入到index对应的地方;
  29. replaceRange(int start, int end, Iterable<E> replacements)使用replacements中的元素替换 List 指定区间([start, end))的元素;
  30. shuffle([Random? random])将 List 中的元素随意打乱(洗牌);
  31. sort([int compare(E a, E b)?])对 List 中的元素排序,其顺序由compare函数指定;
  32. clear()清空 List。

关于 List 的更多细节,请参考官网文档https://api.dart.dev/dart-core/List-class.html