ZetCode

Dart 中的列表推导式

最后修改于 2025 年 6 月 8 日

本教程将使用 collection iffor 语法来探讨 Dart 中的列表推导式。列表推导式允许您以一种简洁、声明式的方式创建和转换列表,这与 Python 的列表推导式类似。

列表推导式概述

Dart 提供了两种强大的声明式列表构建构造:collection ifcollection for。它们允许您在列表字面量中直接使用条件元素和迭代转换来创建列表。

构造 语法 目的
collection if if (condition) element 有条件地包含元素
collection for for (var in iterable) element 转换/生成元素
spread ...iterable 包含多个元素
spread with null ...?iterable 有条件地包含元素

这些构造可以组合起来,以一种简洁、可读的方式创建复杂的列表转换。它们在 Flutter UI 代码中构建小部件列表时尤其有用。

基本 Collection If

collection if 构造有条件地将元素包含在列表中。此示例展示了在创建期间过滤列表元素的各种方法。

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');
}

第一个示例过滤掉负数。第二个示例展示了在条件失败时如何包含交替元素。第三个示例演示了多个条件和嵌套的 spread 以实现管理员权限。

spread 运算符 (...) 对于有条件地组合多个列表特别有用。

$ 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]

基本 Collection For

collection for 构造转换或生成列表元素。此示例展示了各种转换模式。

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');
}

示例展示了数字转换、用于生成对的嵌套循环、复杂对象转换以及矩阵展平。collection for 语法通常消除了对临时变量和命令式循环的需求。

请注意,嵌套循环如何在单个表达式中展平层次化数据结构。这在处理 API 响应或配置数据时尤其有用。

$ 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]

组合 If 和 For

collection ifcollection for 可以组合起来实现强大的列表推导式。此示例演示了复杂的过滤和转换。

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');
}

第一个推导式过滤了有库存的产品并转换了它们的名称。第二个根据价格应用不同的折扣。第三个展示了一个真实的 UI 场景,根据权限构建小部件描述。

这些推导式在执行复杂操作的同时保持了可读性。嵌套的 if 语句演示了如何在单个表达式中处理多个条件。

$ 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]

高级模式

对于更高级的场景,列表推导式可以嵌套并与其他 Dart 功能结合使用。此示例演示了复杂的数据处理。

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');
}

第一个示例将学生数据处理成带有平均分和及格/不及格等级的报告卡。第二个示例使用带索引的嵌套推导式执行矩阵转置。

这些模式展示了列表推导式如何简洁地处理实际数据处理任务。矩阵转置作为单个表达式尤其令人印象深刻。

$ 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]]

来源

Dart 语言之旅:集合运算符
有效的 Dart:集合

Dart 的 collection iffor 语法提供了强大的列表推导式功能。虽然与 Python 风格的推导式不同,但这些构造实现了声明式的列表创建和转换。它们在 Flutter UI 代码和数据处理管道中尤其有价值。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出 所有 Dart 教程