List Comprehensions in Dart
last modified June 8, 2025
This tutorial explores list comprehensions in Dart using collection if
and for
syntax. List comprehensions allow you to create and
transform lists in a concise, declarative way, similar to Python's list
comprehensions.
List Comprehension Overview
Dart offers two powerful constructs for building lists declaratively:
collection if
and collection for
. These allow you to
create lists with conditional elements and iterative transformations directly
within list literals.
Construct | Syntax | Purpose |
---|---|---|
collection if | if (condition) element |
Conditionally include elements |
collection for | for (var in iterable) element |
Transform/generate elements |
spread | ...iterable |
Include multiple elements |
spread with null | ...?iterable |
Conditionally include elements |
These constructs can be combined to create complex list transformations in a concise, readable way. They're particularly useful in Flutter UI code for building lists of widgets.
Basic Collection If
The collection if
construct conditionally includes elements in a
list. This example shows different ways to filter list elements during creation.
void main() { bool includeNegatives = false; var numbers = [-2, -1, 0, 1, 2]; // Simple conditional inclusion var filtered = [ for (var n in numbers) if (n >= 0) n ]; print('Filtered: $filtered'); // Conditional element with else var absolute = [ for (var n in numbers) if (n >= 0 || includeNegatives) n else -n ]; print('Absolute: $absolute'); // Multiple conditions var user = {'name': 'Alice', 'age': 30, 'isAdmin': true}; var permissions = [ 'view', if (user['age'] as int >= 18) 'edit', if (user['isAdmin'] == true) ...[ 'delete', 'configure' ], ]; print('Permissions: $permissions'); // With spread operator var defaultItems = ['home', 'search']; var extraItems = ['profile', 'settings']; var allItems = [ ...defaultItems, if (user['isAdmin'] == true) ...extraItems, 'logout' ]; print('All items: $allItems'); }
The first example filters out negative numbers. The second shows how to include alternate elements when a condition fails. The third demonstrates multiple conditions and nested spreads for admin permissions.
The spread operator (...
) is particularly useful for combining
multiple lists conditionally.
$ dart run basic_if.dart Filtered: [0, 1, 2] Absolute: [2, 1, 0, 1, 2] Permissions: [view, edit, delete, configure] All items: [home, search, profile, settings, logout]
Basic Collection For
The collection for
construct transforms or generates list elements.
This example shows various transformation patterns.
void main() { // Simple transformation var numbers = [1, 2, 3]; var squares = [for (var n in numbers) n * n]; print('Squares: $squares'); // Nested loops var pairs = [ for (var i = 1; i <= 3; i++) for (var j = 1; j <= 2; j++) '($i,$j)' ]; print('Pairs: $pairs'); // Complex transformations var users = [ {'name': 'Alice', 'roles': ['admin', 'user']}, {'name': 'Bob', 'roles': ['user']}, {'name': 'Charlie', 'roles': ['user', 'editor']} ]; var roleList = [ for (var user in users) for (var role in user['roles'] as List<String>) '${user['name']} ($role)' ]; print('Roles: $roleList'); // Combining with spread var matrix = [ [1, 2], [3, 4], [5, 6] ]; var flattened = [ 0, for (var row in matrix) ...row, 7 ]; print('Flattened: $flattened'); }
The examples show numeric transformation, nested loops for generating pairs,
complex object transformations, and matrix flattening. The collection for
syntax often eliminates the need for temporary variables and imperative loops.
Notice how nested loops can flatten hierarchical data structures in a single expression. This is particularly useful when processing API responses or configuration data.
$ dart run basic_for.dart Squares: [1, 4, 9] Pairs: [(1,1), (1,2), (2,1), (2,2), (3,1), (3,2)] Roles: [Alice (admin), Alice (user), Bob (user), Charlie (user), Charlie (editor)] Flattened: [0, 1, 2, 3, 4, 5, 6, 7]
Combining If and For
collection if
and collection for
can be combined for
powerful list comprehensions. This example demonstrates complex filtering and
transformation.
class Product { final String name; final double price; final bool inStock; Product(this.name, this.price, this.inStock); @override String toString() => '$name (\$$price)'; } void main() { var products = [ Product('Laptop', 999.99, true), Product('Phone', 699.99, false), Product('Tablet', 499.99, true), Product('Monitor', 249.99, true), Product('Keyboard', 79.99, false), ]; // Filter and transform var availableProducts = [ for (var p in products) if (p.inStock) p.name.toUpperCase() ]; print('Available: $availableProducts'); // Complex conditions var discounted = [ for (var p in products) if (p.inStock) if (p.price > 500) Product('Premium ${p.name}', p.price * 0.9, true) else Product(p.name, p.price * 0.95, true) ]; print('Discounted: $discounted'); // Real-world example: Widget list var features = ['dark_mode', 'notifications', 'advanced_settings']; var userPermissions = ['dark_mode', 'notifications']; var featureWidgets = [ for (var feature in features) if (userPermissions.contains(feature)) '${feature.replaceAll('_', ' ')} widget' else 'disabled ${feature.replaceAll('_', ' ')} widget' ]; print('Feature widgets: $featureWidgets'); }
The first comprehension filters in-stock products and transforms their names. The second applies different discounts based on price. The third shows a real-world UI scenario building widget descriptions based on permissions.
These comprehensions maintain readability while performing complex operations.
The nested if
statements demonstrate how to handle multiple
conditions in a single expression.
$ dart run combined.dart Available: [LAPTOP, TABLET, MONITOR] Discounted: [Premium Laptop ($899.991), Tablet ($474.9905), Monitor ($237.4905)] Feature widgets: [dark mode widget, notifications widget, disabled advanced settings widget]
Advanced Patterns
For more advanced scenarios, list comprehensions can be nested and combined with other Dart features. This example demonstrates complex data processing.
class Student { final String name; final List<int> grades; final bool isActive; Student(this.name, this.grades, this.isActive); } void main() { var students = [ Student('Alice', [85, 92, 78], true), Student('Bob', [65, 70, 80], true), Student('Charlie', [90, 88, 95], false), ]; // Complex transformation with nested comprehensions var reportCards = [ for (var student in students) if (student.isActive) { 'name': student.name, 'average': student.grades.reduce((a, b) => a + b) / student.grades.length, 'grades': [ for (var grade in student.grades) if (grade >= 70) 'Pass' else 'Fail' ], } ]; print('Report cards:'); for (var card in reportCards) { print('${card['name']}: ${(card['average'] as double).toStringAsFixed(1)}'); print(' Grades: ${card['grades']}'); } // Matrix operations var matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]; var transposed = [ for (var i = 0; i < matrix[0].length; i++) [ for (var row in matrix) row[i] ] ]; print('\nOriginal matrix: $matrix'); print('Transposed matrix: $transposed'); }
The first example processes student data into report cards with averages and pass/fail grades. The second performs matrix transposition using nested comprehensions with indices.
These patterns show how list comprehensions can handle real-world data processing tasks concisely. The matrix transposition is particularly impressive as a single expression.
$ dart run advanced.dart Report cards: Alice: 85.0 Grades: [Pass, Pass, Pass] Bob: 71.7 Grades: [Fail, Pass, Pass] Original matrix: [[1, 2, 3], [4, 5, 6], [7, 8, 9]] Transposed matrix: [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Source
Dart Language Tour: Collection Operators
Effective Dart: Collections
Dart's collection if
and for
syntax provides powerful
list comprehension capabilities. While different from Python-style comprehensions,
these constructs enable declarative list creation and transformation. They're
particularly valuable in Flutter UI code and data processing pipelines.
Author
List all Dart tutorials.