YouTip LogoYouTip

Dart Collections

Collections are data structures 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 a group of ordered elements, and duplicates are allowed. You can access any element in a List through an index (starting from 0). ### Creating a List ## Example ```dart void main() { // Create List using literal List sites = ['TUTORIAL', 'Google', 'GitHub']; print('Website list: $sites'); // Type inference (omitting generic type) var numbers = [1, 2, 3, 4, 5]; print('Number list: $numbers'); // Create empty list var emptyList = []; // Create fixed-length list using List.filled var zeros = List.filled(3, 0); // [0, 0, 0] print('Filled list: $zeros'); // Generate list using List.generate var squares = List.generate(5, (i) => i * i); print('Square list: $squares'); } Website list: [TUTORIAL, Google, GitHub] Number list: [1, 2, 3, 4, 5] Filled list: [0, 0, 0] Square list: [0, 1, 4, 9, 16] ### Accessing and Modifying List Elements ## Example ```dart void main() { var fruits = ['Apple', 'Banana', 'Orange']; // Access through index (starting from 0) print('First fruit: ${fruits}'); // Apple print('Last one: ${fruits[fruits.length - 1]}'); // Orange // Modify element fruits = 'Grape'; print('After modification: $fruits'); // [Apple, Grape, Orange] // Get length print('Fruit count: ${fruits.length}'); // Check if empty print('List empty? ${fruits.isEmpty}'); print('List not empty? ${fruits.isNotEmpty}'); } First fruit: Apple Last one: Orange After modification: [Apple, Grape, Orange] Fruit count: 3 List empty? false List not empty? true ### Common List Operations ## Example ```dart void main() { var list = ['TUTORIAL', 'Dart']; // Add elements list.add('Flutter'); // Add single list.addAll(['Google', 'AI']); // Add multiple print('After adding: $list'); // Insert element (at specified 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 one 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'); } After adding: [TUTORIAL, Dart, Flutter, Google, AI] After insertion: [TUTORIAL, Tutorial, Dart, Flutter, Google, AI] After deletion: [Tutorial, Dart, Flutter] Contains Dart? true, Position: 1 After sorting: [1, 1, 3, 4, 5, 9] After reversal: [9, 5, 4, 3, 1, 1] First 3: [1, 1, 3] ### Functional Methods for List Dart's List supports functional methods such as map, where, and reduce, making data processing more concise. ## Example ```dart void main() { var scores = [55, 78, 92, 60, 45, 88]; // where: filter (keep elements that meet condition) var passed = scores.where((s) => s >= 60); print('Passed scores: $passed'); // map: mapping (convert each element to new value) var grades = scores.map((s) => s >= 60 ? 'Pass' : 'Fail'); print('Grades: $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('TUTORIAL total score: $total'); // fold: cumulative calculation with 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('Has full mark? $hasFullMark'); print('All passed? $allPassed'); } Passed scores: (78, 92, 60, 88) Grades: (Fail, Pass, Pass, Pass, Fail, Pass) High score list: [High score: 92, High score: 88] TUTORIAL total score: 418 Average score: 69.7 Has full mark? false All passed? false > `map()` and `where()` return Iterable (lazy evaluation), which needs to be converted to List using `toList()` to actually execute the calculation. If you only need to iterate once, you can use Iterable directly without conversion. * * * ## Set: Unique Element Collection Set is similar to List, but each element in a Set can only appear once, duplicates are not allowed. Set is unordered, elements cannot be accessed through index. ## Example ```dart void main() { // Create Set (elements automatically deduplicated) Set tags = {'Dart', 'Flutter', 'Dart', 'TUTORIAL'}; print('Tag set: $tags'); // {Dart, Flutter, TUTORIAL}, duplicate Dart is removed print('Tag count: ${tags.length}'); // 3 // Add element tags.add('Google'); tags.add('Dart'); // Dart already exists, won't be added again print('After adding: $tags'); // Delete element tags.remove('Google'); print('After deletion: $tags'); // Check if contains print('Contains TUTORIAL? ${tags.contains('TUTORIAL')}'); // 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} } Tag set: {Dart, Flutter, TUTORIAL} Tag count: 3 After adding: {Dart, Flutter, TUTORIAL, Google} After deletion: {Dart, Flutter, TUTORIAL} Contains TUTORIAL? true Intersection: {3, 4} Union: {1, 2, 3, 4, 5, 6} Difference: {1, 2} > A 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 Mapping Map is used to store key-value pairs (Key-Value Pair), where each key corresponds to one value. Keys in a Map must be unique, values can be duplicated. ### Creating and Accessing Map ## Example ```dart void main() { // Create Map using literal Map siteInfo = { 'name': 'TUTORIAL', 'url': '', 'type': 'Programming Tutorial', }; // Access value through key print('Site name: ${siteInfo['name']}'); print('Site URL: ${siteInfo['url']}'); // Accessing non-existent key returns null print('Description: ${siteInfo['description']}'); // null // Add/modify key-value pair siteInfo['language'] = 'Chinese'; siteInfo['name'] = ''; // Modify value of existing key print('Updated: $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')}'); } Site name: TUTORIAL Site URL: Description: null Updated: {name: , url: type: Programming Tutorial, language: Chinese} All keys: (name, url, type, language) All values: (, Programming Tutorial, Chinese) Has url key? true Has desc key? false ### Common Map Operations ## Example ```dart void main() { var scores = { 'tutorial': 95, 'Alice': 87, 'Bob': 72, }; // Iterate 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; // Doesn't exist, return default value 0 print('Alice: $aliceScore, Eve: $eveScore'); // putIfAbsent: only add when key doesn't exist scores.putIfAbsent('tutorial', () => 100); // Already exists, not added scores.putIfAbsent('David', () => 80); // Doesn't exist, add print('Final: $scores'); // Get length print('Count: ${scores.length}'); } tutorial: 95 points Alice: 87 points Bob: 72 points After deleting Bob: {tutorial: 95, Alice: 87} Alice: 87, Eve: 0 Final: {tutorial: 95, Alice: 87, David: 80} Count: 3 > Map keys 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 ```dart void main() { var basics = ['Dart', 'Flutter']; var advanced = ['Async Programming', 'State Management']; // ... spread operator: insert elements from another collection var allCourses = ['TUTORIAL Intro', ...basics, ...advanced]; print('All courses: $allCourses'); // ...? null-safe spread: if collection is null, skip List? optionalList; // May be null var safeList = ['First item', ...?optionalList]; print('Safe spread: $safeList'); // Only first item optionalList = ['Extra content']; safeList = ['First item', ...?optionalList]; print('Spread with value: $safeList'); } All courses: [TUTORIAL Intro, Dart, Flutter, Async Programming, State Management] Safe spread: Spread with value: [First item, Extra content] ### Collection if and for (Collection Control Flow) Dart allows direct use of if and for in collection literals, which is very practical syntactic sugar. ## Example ```dart void main() { bool showAdmin = true; // Collection if: decide whether to include element based on condition var menuItems = [ 'Home', 'Tutorial', if (showAdmin) 'Admin Panel', // Only added when condition is true 'About', ]; print('Menu: $menuItems'); // Collection for: 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 = [ 'TUTORIAL Home', for (var tag in tags) '', ]; print('Links: $links'); } Menu: [Home, Tutorial, Admin Panel, About] Doubled: [2, 4, 6] Links: [TUTORIAL Home, * * * ## Comparison of Three Collection Types | Feature | List | Set | Map | | --- | --- | --- | --- | | Ordering | Ordered | Unordered | Unordered (but has iteration order) | | Duplicates Allowed | Allowed | Not allowed | Keys not allowed, values allowed | | Index Access | Supports [] | Not supported | Access through key [] | | Typical Scenarios | Ordered list, sequence | Deduplication, tag collection | Key-value mapping, configuration items | | Create Literal | [] | {} | {key: value} | > Common beginner mistake: Both Set and Map use {} for literals. The difference is: Map literals have colons (key: value), while Set doesn't. If you write `var x = {}`, Dart will infer it as Map, not Set. To create an empty Set, you must write `var x = {}`.
← Dart Classes And ObjectsDart Operators β†’