Dart Collections
List, Set, Map + spread, collection for/if
Dart provides 3 core collections: List (ordered, duplicates OK), Set (unique, set operations), and Map (key-value pairs). Spread operator (...) merges collections, collection for/if creates dynamic elements within literals, and method chaining with map/where/fold builds powerful data transformation pipelines.
1. List β μμ μλ 컬λ μ
Listλ μμκ° μκ³ μ€λ³΅μ νμ©νλ κ°μ₯ κΈ°λ³Έμ μΈ μ»¬λ μ μ λλ€. μΈλ±μ€λ‘ μμμ μ κ·Όνλ©°, λ€μν μμ± λ°©μμ μ 곡ν©λλ€.
List μμ±
var fruits = ['μ¬κ³Ό', 'λ°λλ', 'μ€λ μ§'];\nList<String> names = ['νκΈΈλ', 'κΉμ² μ', 'μ΄μν¬'];\nvar emptyList = <int>[];\nvar fixedList = List<int>.filled(5, 0); // [0, 0, 0, 0, 0]\nvar generatedList = List<int>.generate(5, (i) => i * i); // [0, 1, 4, 9, 16]List μ κ·Ό & μ‘°μ
var fruits = ['μ¬κ³Ό', 'λ°λλ', 'μ€λ μ§', 'λΈκΈ°', 'ν¬λ'];\nprint(fruits[0]); // μ¬κ³Ό\nprint(fruits.length); // 5\nprint(fruits.first); // μ¬κ³Ό\n\nfruits.add('ν€μ');\nfruits.addAll(['λ©λ‘ ', 'μλ°']);\nfruits.remove('λ°λλ');\nfruits.removeAt(1);\nfruits.removeWhere((fruit) => fruit.length <= 2);\nfruits.sort();\nprint(fruits.indexOf('ν¬λ'));\nprint(fruits.contains('μ¬κ³Ό')); // trueList λ³ν (map, where, fold, expand)
var numbers = [1, 2, 3, 4, 5];\nvar doubled = numbers.map((n) => n * 2).toList(); // [2, 4, 6, 8, 10]\nvar evenNumbers = numbers.where((n) => n.isEven).toList(); // [2, 4]\nvar sum = numbers.fold<int>(0, (prev, curr) => prev + curr); // 15\nvar product = numbers.reduce((a, b) => a * b); // 120\n\nvar nested = [[1, 2], [3, 4], [5]];\nvar flattened = nested.expand((list) => list).toList(); // [1, 2, 3, 4, 5]List μ¬λΌμ΄μ±
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\nvar slice = numbers.sublist(2, 5); // [3, 4, 5]\nvar copy = List<int>.from(numbers);\nnumbers.replaceRange(0, 3, [99, 98, 97]);\nvar reversed = numbers.reversed.toList();\nnumbers.fillRange(5, 8, 0);2. Set β μ€λ³΅ μλ 컬λ μ
Setμ μ€λ³΅μ νμ©νμ§ μλ 컬λ μ μΌλ‘, μνμ μ§ν© μ°μ°(ν©μ§ν©, κ΅μ§ν©, μ°¨μ§ν©)μ μ§μν©λλ€.
Set μμ±
var fruits = {'μ¬κ³Ό', 'λ°λλ', 'μ€λ μ§'};\nSet<String> names = {'νκΈΈλ', 'κΉμ² μ', 'μ΄μν¬'};\nvar emptySet = <int>{};\nvar numbers = Set<int>.from([1, 2, 2, 3, 3, 3, 4, 5, 5]); // {1, 2, 3, 4, 5}Set μ§ν© μ°μ°
var set1 = {1, 2, 3, 4, 5};\nvar set2 = {4, 5, 6, 7, 8};\n\nvar union = set1.union(set2); // {1, 2, 3, 4, 5, 6, 7, 8}\nvar intersection = set1.intersection(set2); // {4, 5}\nvar difference = set1.difference(set2); // {1, 2, 3}\n\nset1.add(6);\nset1.addAll({7, 8, 9});\nset1.remove(9);\nprint(set1.contains(5)); // true\nprint({1, 2}.isSubsetOf(set1)); // trueSet λ³ν
var numbers = {1, 2, 3, 4, 5};\nvar doubled = numbers.map((n) => n * 2).toSet();\nvar evenNumbers = numbers.where((n) => n.isEven).toSet();\nvar numbersList = numbers.toList();3. Map β ν€-κ° μ 컬λ μ
Mapμ ν€-κ° μμΌλ‘ λ°μ΄ν°λ₯Ό μ μ₯ν©λλ€. ν€λ‘ λΉ λ₯΄κ² κ°μ κ²μν μ μμ΅λλ€.
Map μμ±
var person = {\n 'name': 'νκΈΈλ',\n 'age': 30,\n 'isStudent': false\n};\nMap<String, int> scores = {\n 'μν': 90,\n 'μμ΄': 85,\n 'κ³Όν': 95\n};\nvar emptyMap = <String, dynamic>{};\nvar map2 = Map.from({'a': 1, 'b': 2});\nvar map3 = Map.of({'x': 10, 'y': 20});Map μ κ·Ό & μ‘°μ
print(person['name']); // νκΈΈλ\nprint(person.containsKey('age')); // true\nprint(person.containsValue(30)); // true\nprint(person.keys.toList());\nprint(person.values.toList());\n\nperson['email'] = 'hong@example.com';\nperson['age'] = 31;\nperson.remove('isStudent');\nperson.addAll({'address': 'μμΈμ', 'phone': '010-1234-5678'});\nperson.putIfAbsent('gender', () => 'λ¨μ±');Map λ³ν
var scores = {'μν': 90, 'μμ΄': 85, 'κ³Όν': 95, 'κ΅μ΄': 80};\n\n// mapμΌλ‘ ν€-κ° λ³ν\nvar scaledScores = scores.map((k, v) => MapEntry(k, v * 1.1));\n\n// entries.whereλ‘ νν°λ§\nvar highScores = scores.entries\n .where((entry) => entry.value >= 90);\n\n// forEachλ‘ μν\nscores.forEach((key, value) {\n print('$key: $value');\n});4. λ°λ³΅λ¬Έ (Loops)
Dartλ for, for-in, while, do-while, forEach λ± λ€μν λ°λ³΅ λ°©μμ μ 곡ν©λλ€.
// κΈ°λ³Έ for 루ν\nfor (int i = 0; i < 5; i++) {\n print(i);\n}\n\n// for-in 루ν\nvar fruits = ['μ¬κ³Ό', 'λ°λλ', 'μ€λ μ§'];\nfor (var fruit in fruits) {\n print(fruit);\n}\n\n// while 루ν\nint count = 0;\nwhile (count < 5) {\n print(count);\n count++;\n}\n\n// forEach λ©μλ\nvar numbers = [1, 2, 3, 4, 5];\nnumbers.forEach((number) {\n print(number * 2);\n});\n\n// Map forEach\nvar scores = {'μν': 90, 'μμ΄': 85, 'κ³Όν': 95};\nscores.forEach((subject, score) {\n print('$subject: $scoreμ ');\n});루ν μ μ΄ (break, continue, λ μ΄λΈ)
// break β 루ν μ¦μ μ’
λ£\nfor (int i = 0; i < 10; i++) {\n if (i == 5) break;\n print(i); // 0, 1, 2, 3, 4\n}\n\n// continue β νμ¬ λ°λ³΅ 건λλ°κΈ°\nfor (int i = 0; i < 5; i++) {\n if (i == 2) continue;\n print(i); // 0, 1, 3, 4\n}\n\n// λ μ΄λΈλ‘ μ€μ²© 루ν μ μ΄\nouterLoop: for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == 1 && j == 1) {\n break outerLoop;\n }\n print('$i, $j');\n }\n}5. μ€νλ λ μ°μ°μ (...)
μ€νλ λ μ°μ°μλ₯Ό μ¬μ©νλ©΄ 컬λ μ
μ λͺ¨λ μμλ₯Ό λ€λ₯Έ 컬λ μ
μμ νΌμΉ μ μμ΅λλ€. null-aware μ€νλ λ(...?)λ μ§μν©λλ€.
var list1 = [1, 2, 3];\nvar list2 = [0, ...list1, 4, 5]; // [0, 1, 2, 3, 4, 5]\n\n// null-aware μ€νλ λ\nList<int>? nullableList;\nvar combined = [0, ...?nullableList, 1]; // [0, 1]\n\n// Map μ€νλ λ\nvar map1 = {'a': 1, 'b': 2};\nvar map2 = {'c': 3, ...map1}; // {'c': 3, 'a': 1, 'b': 2}\n\n// Set μ€νλ λ\nvar set1 = {1, 2, 3};\nvar set2 = {0, ...set1, 4}; // {0, 1, 2, 3, 4}6. 컬λ μ for / if
컬λ μ
리ν°λ΄ μμμ forμ ifλ₯Ό μ¬μ©νμ¬ λμ μΌλ‘ μμλ₯Ό μμ±ν μ μμ΅λλ€.
// 컬λ μ
for\nvar numbers = [1, 2, 3];\nvar doubled = [\n 0,\n for (var n in numbers) n * 2,\n 4\n]; // [0, 2, 4, 6, 4]\n\n// 컬λ μ
if\nbool includeZ = true;\nvar letters = ['a', 'b', if (includeZ) 'z']; // ['a', 'b', 'z']\n\n// μ€μ νμ© β μ‘°κ±΄λΆ UI 리μ€νΈ ꡬμ±\nvar items = [\n 'home',\n if (userLoggedIn) 'profile',\n for (var item in defaultItems) item,\n if (isAdmin) 'admin'\n];7. μ λλ μ΄ν° (sync* / async*)
μ λλ μ΄ν° ν¨μλ yieldλ₯Ό μ¬μ©νμ¬ κ°μ νλμ© μμ±ν©λλ€. λκΈ° μ λλ μ΄ν°(sync*)λ Iterableμ, λΉλκΈ° μ λλ μ΄ν°(async*)λ Streamμ λ°νν©λλ€.
λκΈ° μ λλ μ΄ν° (sync*)
Iterable<int> getNumbers(int n) sync* {\n for (int i = 0; i < n; i++) {\n yield i;\n }\n}\n\nvoid main() {\n for (var num in getNumbers(5)) {\n print(num); // 0, 1, 2, 3, 4\n }\n}λΉλκΈ° μ λλ μ΄ν° (async*)
Stream<int> countStream(int n) async* {\n for (int i = 1; i <= n; i++) {\n await Future.delayed(Duration(seconds: 1));\n yield i;\n }\n}\n\nvoid main() async {\n await for (var num in countStream(5)) {\n print(num); // 1μ΄λ§λ€ 1, 2, 3, 4, 5\n }\n}8. κ³ κΈ λ³ν & λ©μλ 체μ΄λ
μ¬λ¬ λ©μλλ₯Ό 체μ΄λνμ¬ λ°μ΄ν° λ³ν νμ΄νλΌμΈμ ꡬμ±ν μ μμ΅λλ€.
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\nvar result = numbers\n .where((n) => n % 2 == 0) // μ§μ νν°\n .map((n) => n * n) // μ κ³±\n .takeWhile((n) => n <= 36) // 36 μ΄νλ§\n .fold(0, (sum, n) => sum + n); // ν©κ³\n\n// κ·Έλ£Ήν\nvar fruits = ['μ¬κ³Ό', 'λ°λλ', '체리', 'λΈλ£¨λ² 리', 'μ보카λ'];\nvar byFirstLetter = fruits.fold<Map<String, List<String>>>({}, (map, fruit) {\n var firstLetter = fruit[0];\n map[firstLetter] = (map[firstLetter] ?? [])..add(fruit);\n return map;\n});9. μΊμ€μΌμ΄λ νκΈ°λ² (..)
μΊμ€μΌμ΄λ μ°μ°μ(..)λ₯Ό μ¬μ©νλ©΄ λμΌ κ°μ²΄μ μ°μμΌλ‘ λ©μλλ₯Ό νΈμΆν μ μμ΅λλ€.
var list = [1, 2, 3]\n ..add(4)\n ..addAll([5, 6])\n ..remove(2)\n ..sort();\n\nvar map = {'user': {'name': 'νκΈΈλ', 'age': 30}}\n ..['user']['email'] = 'hong@example.com'\n ..['user']['age'] = 31\n ..['active'] = true;10. Null-Aware 컬λ μ μ‘°μ
nullable 컬λ μ μ μμ νκ² λ€λ£¨λ ν¨ν΄μ λλ€.
List<String>? nullableList;\nnullableList?.add('νλͺ©'); // nullμ΄λ©΄ 무μ\nvar list = nullableList ?? []; // nullμ΄λ©΄ λΉ λ¦¬μ€νΈ\nlist.add('νλͺ©');\n\nMap<String, int>? scoresMap;\nscoresMap ??= {}; // nullμ΄λ©΄ λΉ λ§΅ ν λΉ\nscoresMap['μν'] = 90;11. μ€μ μμ β νμ λ°μ΄ν° νμ΄νλΌμΈ
μ€μ μμ μμ£Ό μ¬μ©νλ 컬λ μ νμ© ν¨ν΄μ λλ€. κ°μ²΄ 리μ€νΈλ₯Ό map/foldλ‘ λ³ννμ¬ μ§κ³ν©λλ€.
class Student {\n final String name;\n final int age;\n final Map<String, int> scores;\n Student(this.name, this.age, this.scores);\n}\n\nvoid main() {\n final students = [\n Student('νκΈΈλ', 20, {'μν': 90, 'μμ΄': 85, 'κ³Όν': 95}),\n Student('κΉμ² μ', 22, {'μν': 75, 'μμ΄': 90, 'κ³Όν': 85}),\n Student('μ΄μν¬', 21, {'μν': 85, 'μμ΄': 92, 'κ³Όν': 88}),\n Student('λ°λ―Όμ', 23, {'μν': 95, 'μμ΄': 80, 'κ³Όν': 92}),\n ];\n\n final averageScores = students.map((student) {\n final total = student.scores.values\n .fold<int>(0, (sum, score) => sum + score);\n final average = total / student.scores.length;\n return {'name': student.name, 'average': average};\n }).toList();\n}컬λ μ λΉκ΅ μμ½
| 컬λ μ | μμ | μ€λ³΅ | μ κ·Ό λ°©μ | μ£Όμ μ©λ |
|---|---|---|---|---|
| List | O | O | μΈλ±μ€ [i] | μμ μλ λ°μ΄ν°, λ°°μ΄ |
| Set | X | X | contains() | μ€λ³΅ μ κ±°, μ§ν© μ°μ° |
| Map | X | ν€ X / κ° O | ν€ [key] | ν€-κ° λ§€ν, JSON |
ν΅μ¬ μ 리
- List β κ°μ₯ λ²μ©μ .
map/where/foldλ‘ ν¨μν νμ΄νλΌμΈ κ΅¬μ± - Set β μ€λ³΅ μ κ±°κ° νμν λ.
union/intersection/differenceλ‘ μ§ν© μ°μ° - Map β ν€λ‘ λΉ λ₯Έ κ²μ.
putIfAbsent/entries.whereλ‘ μ‘°κ±΄λΆ μ‘°μ - μ€νλ λ & 컬λ μ for/if β 리ν°λ΄ μμμ λμ 컬λ μ μμ±
- μ λλ μ΄ν° β
sync*(Iterable) /async*(Stream)λ‘ κ°μ μ§μ° μμ±
Implementation Steps
List β add/addAll to insert, map/where/fold for transform/filter/aggregate, method chaining for pipelines
Set β union/intersection/difference for set operations, useful for deduplication
Map β putIfAbsent (add only if key missing), entries.where for filtering, map() for key-value transform
Spread & collection for/if β [...list1, ...list2] merge, [for (var x in items) x.name], [if (flag) item]
Pros
- ✓ Functional-style data pipelines with method chaining
- ✓ Dynamic list creation within literals using spread/collection forΒ·if
Cons
- ✗ Long chaining reduces readability