ZetCode

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.

basic_if.dart
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.

basic_for.dart
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.

combined.dart
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.

advanced.dart
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

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.