在 C 里,批量数据只有两个选择:定长数组和手写链表,扩容、去重、查找都要自己实现。Dart 内置三大集合——List、Set、Map,把动态扩容、哈希查找、去重这些脏活全部接管;再配合 Iterable 的惰性求值与 Records 元组,处理数据的代码量能压到 C 的几分之一。本章从 List 与 C 数组的差异讲起,覆盖集合字面量、展开语法、collection-if/for、惰性迭代方法,最后落到 Dart 3 的 Records。
一、List 与 C 数组对比
C 数组是「一块固定内存 + 下标访问」,长度编译期确定或由 malloc 手工管理;Dart 的 List 是对象,长度可变,越界访问抛异常而不是踩到未定义行为。
/* C:手写哈希表要处理哈希函数、冲突、扩容、释放,上百行起步 */typedef struct { char key[32]; int value; int used; } Slot;Slot table[100];unsigned hash(const char *s) { unsigned h = 0; while (*s) h = h * 31 + *s++; return h; }
维度
C 手写哈希表
Dart Map
实现成本
哈希函数、冲突、扩容全手写
语言内置
查找复杂度
O(1) 期望
O(1) 期望
键类型
通常限定字符串/整数
任意重写了 == 与 hashCode 的类型
内存管理
手动 malloc/free
GC
遍历
手动扫桶
entries / keys / values
六、展开运算符与 collection-if/for
void main() { final a = [1, 2]; print([0, ...a, 3]); // [0, 1, 2, 3],... 展开 List<int>? maybe = null; print([0, ...?maybe, 3]); // [0, 3],...? 遇 null 直接跳过 final map1 = {'a': 1}; print({'b': 2, ...map1}); // {b: 2, a: 1},后者覆盖同名键 print({0, ...{1, 2}}); // {0, 1, 2},Set 同样支持展开 // collection-if:只保留及格的 final scores = [88, 45, 92, 60]; final passed = [for (final s in scores) if (s >= 60) s]; print(passed); // [88, 92, 60] // collection-for + 索引 final labels = [for (var i = 0; i < scores.length; i++) '第${i + 1}题:${scores[i]}']; print(labels); // [第1题:88, 第2题:45, 第3题:92, 第4题:60] final debug = true; final config = { 'name': 'app', if (debug) 'logLevel': 'verbose', // 条件键值对 for (var i = 0; i < 2; i++) 'k$i': i, // 循环生成键值对 }; print(config); // {name: app, logLevel: verbose, k0: 0, k1: 1}}
flowchart LR
A["集合字面量 [...]"] --> B{"遇到 collection-if"}
B -->|条件为真| C["加入该元素"]
B -->|条件为假| D["跳过"]
A --> E{"遇到 collection-for"}
E --> F["每次迭代求值表达式"]
F --> G["依次加入结果集合"]
题目给出 n 名学生的语文、数学、英语成绩,两名学生「旗鼓相当」的定义是:各科成绩差都不超过 5,且总分差不超过 10。要求统计这样的学生对数。要点是用循环建立二维成绩表,用双重循环枚举所有学生对,内层用 every 或逐个绝对值判断。
import 'dart:io';void main() { final lines = stdin.readAsLinesSync().where((l) => l.trim().isNotEmpty).toList(); final n = int.parse(lines[0].trim()); // scores[i] = [语文, 数学, 英语] final scores = <List<int>>[ for (var i = 1; i <= n; i++) lines[i].trim().split(RegExp(r'\s+')).map(int.parse).toList(), ]; final totals = [for (final s in scores) s.reduce((a, b) => a + b)]; var count = 0; for (var i = 0; i < n; i++) { for (var j = i + 1; j < n; j++) { // 三科差值绝对值都不超过 5 final close = List.generate(3, (k) => (scores[i][k] - scores[j][k]).abs()) .every((d) => d <= 5); if (close && (totals[i] - totals[j]).abs() <= 10) count++; } } print(count);}