Collection If & Collection For
Collection If & Collection For
One of Dart's most distinctive and powerful features is the ability to use control flow directly inside collection literals. You can conditionally include elements and loop inline — all within [], {}, or <> brackets. This makes building dynamic lists and maps dramatically cleaner, especially in Flutter.
🔹 What Are Collection Operators?
Traditional approach to building a list dynamically:
dartvoid main() { bool showBonus = true; List<String> items = ['Apple', 'Banana']; if (showBonus) { items.add('Cherry'); } print(items); // [Apple, Banana, Cherry] }
With collection if, you can do this inline:
dartvoid main() { bool showBonus = true; List<String> items = [ 'Apple', 'Banana', if (showBonus) 'Cherry', ]; print(items); // [Apple, Banana, Cherry] }
The list builds itself based on the condition — no mutation needed!
🔹 Collection If
Syntax:
dart[ element1, if (condition) elementIfTrue, element2, ]
With else
dartvoid main() { bool isPremium = false; List<String> menuItems = [ 'Home', 'Profile', if (isPremium) 'Premium Dashboard' else 'Upgrade to Premium', 'Settings', 'Logout', ]; print(menuItems); // [Home, Profile, Upgrade to Premium, Settings, Logout] }
Multiple Conditional Elements
dartvoid main() { bool isAdmin = true; bool isDeveloper = false; List<String> permissions = [ 'read', 'write', if (isAdmin) 'delete', if (isAdmin) 'manage_users', if (isDeveloper) 'access_logs', if (isDeveloper) 'run_migrations', ]; print(permissions); // [read, write, delete, manage_users] }
Collection If with Maps and Sets
Collection if works with all collection types:
dartvoid main() { bool includeEmail = true; // Map with conditional entry Map<String, String> userInfo = { 'name': 'Alice', 'phone': '+91-9876543210', if (includeEmail) 'email': 'alice@example.com', }; print(userInfo); // {name: Alice, phone: +91-9876543210, email: alice@example.com} // Set with conditional element bool hasProBadge = true; Set<String> badges = { 'member', 'active', if (hasProBadge) 'pro', }; print(badges); // {member, active, pro} }
🔹 Collection For
Syntax:
dart[ for (var item in iterable) expression, ]
Transform every element of an iterable inline — like a concise version of .map():
dartvoid main() { List<int> numbers = [1, 2, 3, 4, 5]; // Double every number List<int> doubled = [ for (var n in numbers) n * 2, ]; print(doubled); // [2, 4, 6, 8, 10] }
Equivalent of a Traditional for Loop
dartvoid main() { // Traditional List<String> labels1 = []; for (int i = 1; i <= 5; i++) { labels1.add('Item $i'); } // Collection for List<String> labels2 = [ for (int i = 1; i <= 5; i++) 'Item $i', ]; print(labels1); // [Item 1, Item 2, Item 3, Item 4, Item 5] print(labels2); // [Item 1, Item 2, Item 3, Item 4, Item 5] }
Collection For with Maps
dartvoid main() { List<String> fruits = ['Apple', 'Banana', 'Cherry']; // Create a Map from a List Map<String, int> fruitLengths = { for (var fruit in fruits) fruit: fruit.length, }; print(fruitLengths); // {Apple: 5, Banana: 6, Cherry: 6} }
🔹 Combining Collection If and Collection For
The real power comes from combining them:
dartvoid main() { List<int> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // Include only even numbers, squared List<int> evenSquares = [ for (var n in numbers) if (n % 2 == 0) n * n, ]; print(evenSquares); // [4, 16, 36, 64, 100] }
dartvoid main() { List<String> allUsers = ['Alice', 'Bob', 'Charlie', 'Dave']; List<String> blockedUsers = ['Bob']; // Build a list excluding blocked users List<String> activeUsers = [ for (var user in allUsers) if (!blockedUsers.contains(user)) user, ]; print(activeUsers); // [Alice, Charlie, Dave] }
🔹 Spread Operator ...
The spread operator inserts all elements of a collection into another:
dartvoid main() { List<int> list1 = [1, 2, 3]; List<int> list2 = [4, 5, 6]; // Merge two lists List<int> merged = [...list1, ...list2]; print(merged); // [1, 2, 3, 4, 5, 6] // Insert in the middle List<int> extended = [0, ...list1, 99, ...list2, 100]; print(extended); // [0, 1, 2, 3, 99, 4, 5, 6, 100] }
Null-Aware Spread ...?
Use ...? when the list might be null — it safely spreads nothing if the value is null:
dartvoid main() { List<String>? extraItems; // null List<String> menu = [ 'Home', 'Profile', ...?extraItems, // safely ignored when null 'Logout', ]; print(menu); // [Home, Profile, Logout] // Now with a value extraItems = ['Settings', 'Help']; List<String> menu2 = [ 'Home', 'Profile', ...?extraItems, 'Logout', ]; print(menu2); // [Home, Profile, Settings, Help, Logout] }
🔹 Why These Are Powerful in Flutter
In Flutter, your entire UI is built from nested expressions. Collection operators fit perfectly because they let you write clean, conditional widget lists without breaking out of the expression tree.
Without Collection If (messy):
dart// Flutter preview List<Widget> buildItems(bool isLoggedIn) { List<Widget> items = [ const ListTile(title: Text('Home')), const ListTile(title: Text('About')), ]; if (isLoggedIn) { items.add(const ListTile(title: Text('Dashboard'))); items.add(const ListTile(title: Text('Logout'))); } else { items.add(const ListTile(title: Text('Login'))); } return items; }
With Collection If (clean):
dart// Flutter preview List<Widget> buildItems(bool isLoggedIn) => [ const ListTile(title: Text('Home')), const ListTile(title: Text('About')), if (isLoggedIn) ...[ const ListTile(title: Text('Dashboard')), const ListTile(title: Text('Logout')), ] else const ListTile(title: Text('Login')), ];
Tip: You can combine if with ... spread to conditionally add multiple widgets at once: if (condition) ...[widget1, widget2]
🔹 Real-World Examples
Example 1: Building a Shopping Cart
dartvoid main() { List<Map<String, dynamic>> cartItems = [ {'name': 'Laptop', 'price': 999.99}, {'name': 'Mouse', 'price': 29.99}, {'name': 'Keyboard', 'price': 79.99}, ]; bool hasCoupon = true; double discount = 50.0; List<String> receipt = [ '=== RECEIPT ===', for (var item in cartItems) '${item['name']}: \$${item['price']}', if (hasCoupon) 'Coupon Discount: -\$$discount', '===============', ]; receipt.forEach(print); }
Output:
=== RECEIPT ===
Laptop: $999.99
Mouse: $29.99
Keyboard: $79.99
Coupon Discount: -$50.0
===============
Example 2: Flattening Nested Lists
dartvoid main() { List<List<int>> matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; // Flatten the matrix into a single list List<int> flat = [ for (var row in matrix) for (var value in row) value, ]; print(flat); // [1, 2, 3, 4, 5, 6, 7, 8, 9] }
Example 3: Dynamic Navigation Menu
dartvoid main() { bool isAdmin = true; bool isVerified = true; List<String> navItems = [ 'Home', 'Browse', if (isVerified) 'My Orders', if (isVerified) 'Profile', if (isAdmin) ...['Admin Panel', 'User Management', 'Reports'], 'Help', 'Logout', ]; navItems.forEach(print); }
Summary
| Feature | Syntax | Purpose |
|---|---|---|
| Collection if | [if (cond) element] | Conditionally include an element |
| Collection if-else | [if (cond) a else b] | Choose between two elements |
| Collection for (for-in) | [for (var x in list) expr] | Transform/iterate inline |
| Collection for (classic) | [for (int i=0; i<n; i++) expr] | Build with index inline |
| Spread | [...list] | Insert all elements of a list |
| Null-aware spread | [...?nullableList] | Safely spread a nullable list |
These collection operators are one of Dart's most elegant features. They reduce boilerplate, improve readability, and are essential for clean Flutter UI code. Up next: loops — for, while, and do-while!