Dart Collection Types
A collection is a data structure used to store multiple data items.
Dart has three built-in core collection types: List, Set, and Map. This chapter will introduce their usage one by one.
List: Ordered List
List is the most commonly used collection type, used to store an ordered group of elements, allowing duplicates.
You can access any element in a List by its index (starting from 0).
Create List
Example
// Create a List using literals
List<String> sites = ['EXAMPLE', 'Google', 'GitHub'];
print(Website list: $sites);
// Type inference (generic types omitted)
var numbers = [1, 2, 3, 4, 5];
print(Number list: $numbers);
// Create an empty list
var emptyList = <String>[];
// Create a fixed-length list using List.filled
var zeros = List.filled(3, 0); // [0, 0, 0]
print(Filled list: $zeros);
// Generate a list using List.generate
var squares = List.generate(5, (i) => i * i);
print(Square numbers list: $squares);
}
网站列表: [EXAMPLE, Google, GitHub] 数字列表: [1, 2, 3, 4, 5] 填充列表: [0, 0, 0] 平方数列表: [0, 1, 4, 9, 16]
Accessing and Modifying List Elements
Example
var fruits = [Apple, Banana, Orange];
// Access by index (starting from 0)
print('First fruit: ${fruits[0]}'); // Apple
print('Last: ${fruits[fruits.length - 1]}'); // Orange
// Modify element
fruits[1] = 'Grape';
print('After modification: $fruits'); // [apple, grape, orange]
// Get length
print('Fruit count: ${fruits.length}');
// Check if empty
print('Is the list empty? ${fruits.isEmpty}');
print('Is the list non-empty? ${fruits.isNotEmpty}');
}
第一个水果: 苹果 最后一个: 橙子 修改后: [苹果, 葡萄, 橙子] 水果数量: 3 列表为空? false 列表非空? true
Common List Operations
Example
var list = ['EXAMPLE', 'Dart'];
// Add elements
list.add('Flutter'); // Add single
list.addAll(['Google', 'AI']); // Add multiple
print('After adding: $list');
// Insert element (at specific position)
list.insert(1, 'Tutorial');
print('After insertion: $list');
// Delete elements
list.remove('AI'); // Delete by value
list.removeAt(0); // Delete by index
list.removeLast(); // Delete last
print('After deletion: $list');
// Find element
bool hasDart = list.contains('Dart');
int index = list.indexOf('Dart');
print('Contains Dart? $hasDart, position: $index');
// Sort
var nums = [3, 1, 4, 1, 5, 9];
nums.sort();
print('After sorting: $nums');
// Reverse
var reversed = nums.reversed.toList();
print('After reversal: $reversed');
// Get sublist
var subList = nums.sublist(0, 3);
print('First 3: $subList');
}
添加后: [EXAMPLE, Dart, Flutter, Google, AI] 插入后: [EXAMPLE, 教程, Dart, Flutter, Google, AI] After deletion: [教程, Dart, Flutter] 包含 Dart? true, 位置: 1 排序后: [1, 1, 3, 4, 5, 9] 反转后: [9, 5, 4, 3, 1, 1] 前3个: [1, 1, 3]
Functional Methods on List
Dart's List supports functional methods like map, where, and reduce, making data processing more concise.
Example
var scores = [55, 78, 92, 60, 45, 88];
// where: filter (retain elements that satisfy the condition)
var passed = scores.where((s) => s >= 60);
print('Passing score: $passed');
// map: mapping (convert each element to a new value)
var grades = scores.map((s) => s >= 60 ? 'Pass' : 'Fail');
print('Grade: $grades');
// where + map chained call
var highScores = scores
.where((s) => s >= 80)
.map((s) => 'High score: $s')
.toList();
print('High score list: $highScores');
// reduce: cumulative calculation
var total = scores.reduce((sum, s) => sum + s);
print('EXAMPLE total score: $total');
// fold: cumulative calculation with an initial value
var avg = scores.fold(0, (sum, s) => sum + s) / scores.length;
print('Average score: ${avg.toStringAsFixed(1)}');
// any / every: existence check
bool hasFullMark = scores.any((s) => s == 100);
bool allPassed = scores.every((s) => s >= 60);
print('Is there a perfect score? $hasFullMark');
print('All passed? $allPassed');
}
及格分数: (78, 92, 60, 88) 评级: (不及格, 及格, 及格, 及格, 不及格, 及格) 高分列表: [高分: 92, 高分: 88] EXAMPLE 总分: 418 平均分: 69.7 有满分吗? false 全部及格? false
map() and where() return an Iterable (lazy evaluation). You need to convert it to a List with toList() for the computation to actually execute. If you only need to iterate once, you can use the Iterable directly without conversion.
Set: Collection of Unique Elements
Set is similar to List, but each element in a Set can appear only once; duplicates are not allowed.
Set is unordered, and elements cannot be accessed by index.
Example
// Create a Set (elements are automatically deduplicated)
Set<String> tags = {'Dart', 'Flutter', 'Dart', 'EXAMPLE'};
print('Tag set: $tags'); // {Dart, Flutter, EXAMPLE}, the duplicate Dart was removed
print('Tag count: ${tags.length}'); // 3
// Add elements
tags.add('Google');
tags.add('Dart'); // Dart already exists, it will not be added again
print('After adding: $tags');
// Delete elements
tags.remove('Google');
print('After deleting: $tags');
// Check if contains
print('Contains EXAMPLE? ${tags.contains('EXAMPLE')}');
// Set operations
var setA = {1, 2, 3, 4};
var setB = {3, 4, 5, 6};
print('Intersection: ${setA.intersection(setB)}'); // {3, 4}
print('Union: ${setA.union(setB)}'); // {1, 2, 3, 4, 5, 6}
print('Difference: ${setA.difference(setB)}'); // {1, 2}
}
标签集合: {Dart, Flutter, EXAMPLE}
标签数量: 3
添加后: {Dart, Flutter, EXAMPLE, Google}
After deletion: {Dart, Flutter, EXAMPLE}
包含 EXAMPLE? true
交集: {3, 4}
并集: {1, 2, 3, 4, 5, 6}
差集: {1, 2}
The typical use case for Set is deduplication. When you don't need duplicate elements, using Set is much more efficient than manually deduplicating with List.
Map: Key-Value Pair Mapping
Map is used to store key-value pairs. Each key corresponds to a value.
Keys in a Map must be unique; values can be duplicated.
Creating and Accessing Map
Example
// Create a Map with literals
Map<String, String> siteInfo = {
'name': 'EXAMPLE',
'url': 'https://www.example.com',
'type': 'Programming Tutorial',
};
// Access value by key
print('Site name: ${siteInfo['name']}');
print('Site URL: ${siteInfo['url']}');
// Accessing a nonexistent key returns null
print('Description: ${siteInfo['description']}'); // null
// Add/Modify key-value pairs
siteInfo['language'] = 'Chinese';
siteInfo['name'] = 'example.com'; // Modify the value of an existing key
print('After update: $siteInfo');
// Get all keys and all values
print('All keys: ${siteInfo.keys}');
print('All values: ${siteInfo.values}');
// Check if key exists
print('Has url key? ${siteInfo.containsKey('url')}');
print('Has desc key? ${siteInfo.containsKey('desc')}');
}
站点名称: EXAMPLE
站点 URL: https://www.example.com
描述: null
更新后: {name: example.com, url: https://www.example.com, type: 编程教程, language: 中文}
所有键: (name, url, type, language)
所有值: (example.com, https://www.example.com, 编程教程, 中文)
有 url 键? true
有 desc 键? false
Common Map Operations
Example
var scores = {
'example': 95,
'Alice': 87,
'Bob': 72,
};
// Iterate over Map
scores.forEach((name, score) {
print('$name: $score points');
});
// Delete key-value pair
scores.remove('Bob');
print('After deleting Bob: $scores');
// Get value or default value
int aliceScore = scores['Alice'] ?? 0;
int eveScore = scores['Eve'] ?? 0; // If absent, return default value 0
print('Alice: $aliceScore, Eve: $eveScore');
// putIfAbsent: add only when the key is absent
scores.putIfAbsent('example', () => 100); // Already exists, do not add
scores.putIfAbsent('David', () => 80); // If absent, add
print('Final: $scores');
// Get length
print('Number of people: ${scores.length}');
}
example: 95 分
Alice: 87 分
Bob: 72 分
删除 Bob 后: {example: 95, Alice: 87}
Alice: 87, Eve: 0
最终: {example: 95, Alice: 87, David: 80}
人数: 3
Keys in a Map can be of any type (String, int, etc.), but key equality must be meaningful. When using custom objects as keys, you need to ensure that == and hashCode are correctly implemented.
Collection spread operators ... and ...?
The spread operator can "spread" the elements of one collection into another collection.
Example
var basics = ['Dart', 'Flutter'];
var advanced = ['Asynchronous programming', 'State management'];
// ... spread operator: insert elements from another collection
var allCourses = ['EXAMPLE Getting Started', ...basics, ...advanced];
print('All courses: $allCourses');
// ...? null-aware spread: skip if collection is null
List<String>? optionalList; // May be null
var safeList = ['First item', ...?optionalList];
print('Safe spread: $safeList'); // Only the first item
optionalList = ['Extra content'];
safeList = ['First item', ...?optionalList];
print('Non-null spread: $safeList');
}
所有课程: [EXAMPLE 入门, Dart, Flutter, 异步编程, 状态管理] 安全展开: [第一项] 有值展开: [第一项, 额外内容]
if and for in collections (collection control flow)
Dart allows using if and for directly in collection literals; this is very useful syntactic sugar.
Example
bool showAdmin = true;
// Collection if: conditionally include elements
var menuItems = [
'Home',
'Tutorial',
if (showAdmin) 'Admin panel', // Add only when condition is true
'About',
];
print('Menu: $menuItems');
// for in a collection: generate elements from another collection
var numbers = [1, 2, 3];
var doubled = [
for (var n in numbers) n * 2, // Iterate to generate new elements
];
print(Doubled: $doubled);
// if + for can be combined
var tags = ['Dart', 'Flutter'];
var links = [
'EXAMPLE Home',
for (var tag in tags) 'https://example.com/$tag',
];
print('Links: $links');
}
菜单: [首页, 教程, 管理后台, 关于] 翻倍: [2, 4, 6] 链接: [EXAMPLE 首页, https://example.com/Dart, https://example.com/Flutter]
Comparison of Three Collections
| Features | List | Set | Map |
|---|---|---|---|
| ordering | Ordered | Unordered | Unordered (but has iteration order) |
| Duplicates allowed | Allowed | Not allowed | Keys must be unique, values may be duplicated |
| Index access | Supports [] | Not supported | Access via key [] |
| Typical scenarios | Ordered List, Sequence | Deduplication, Tag Collection | Key-value mapping, configuration items |
| Create literals | [] | {} | {key: value} |
Notes
Set and Map both use{}As a literal.
The difference is:
- Map usagekey: valueForm (with colon)
- Set directly writes elements (without a colon)
For example:
var map = {'name': 'Tom'}; // Map
var set = {'Tom', 'Jerry'}; // Set
Special attention needed:
var x = {};
This will not create an empty Set; instead, Dart will infer it as:
Map<dynamic, dynamic>
Because empty curly braces cannot determine the element type, Dart treats it as a Map by default.
To create an empty Set, you must explicitly specify:
var x = <String>{};
or
:
Set<String> x = {};other extensions