Multiple Approaches to Enumerate Lists with Index and Value in Dart

Nov 23, 2025 · Programming · 6 views · 7.8

Keywords: Dart | List Iteration | Index Access | asMap Method | indexed Property | Extension Methods

Abstract: This technical article comprehensively explores various methods for iterating through lists while accessing both element indices and values in the Dart programming language. The analysis begins with the native asMap() method, which provides index access through map conversion. The discussion then covers the indexed property introduced in Dart 3, which tracks iteration state for index retrieval. Supplementary approaches include the mapIndexed and forEachIndexed extension methods from the collection package, along with custom extension implementations. Each method is accompanied by complete code examples and performance analysis, enabling developers to select optimal solutions based on specific requirements.

Introduction

List iteration represents one of the most fundamental and frequently performed operations in software development. Many programming scenarios require not only access to list element values but also their positional indices within the list. This requirement is particularly common in data processing, UI rendering, and algorithm implementation. Dart, as a modern cross-platform development language, provides multiple elegant solutions to address this need.

Implementing Indexed Iteration with asMap() Method

The Dart standard library's List class provides the asMap() method, which converts a list into a Map object where keys represent element indices (zero-based integers) and values correspond to list elements. This conversion enables us to utilize Map iteration methods for simultaneous access to indices and values.

Below is the fundamental implementation principle of the asMap() method:

class List<E> {
  Map<int, E> asMap() {
    return Map<int, E>.fromIterables(
      Iterable<int>.generate(this.length),
      this
    );
  }
}

Practical application example:

void main() {
  final sampleList = ['apple', 'banana', 'orange'];
  
  // Using forEach for iteration
  sampleList.asMap().forEach((index, value) {
    print('Index: $index, Value: $value');
  });
  
  // Using map for transformation
  final transformed = sampleList.asMap().entries.map((entry) {
    return 'Element ${entry.key} is ${entry.value}';
  }).toList();
  
  print(transformed);
}

Advantages of this approach:

The indexed Property in Dart 3

With the release of Dart 3, the language introduced the indexed property, specifically designed to address indexed iteration challenges. The indexed property returns an Iterable where each element constitutes a tuple containing both index and value.

Implementation principle analysis:

extension on Iterable<E> {
  Iterable<(int, E)> get indexed sync* {
    var index = 0;
    for (final element in this) {
      yield (index++, element);
    }
  }
}

Usage example:

void main() {
  final fruits = ['apple', 'banana', 'orange'];
  
  // Using for-in loop
  for (final (index, fruit) in fruits.indexed) {
    print('Position $index: $fruit');
  }
  
  // Combining with other iteration methods
  final descriptions = fruits.indexed.map(((int, String) pair) {
    final (index, fruit) = pair;
    return 'Fruit $index: $fruit';
  }).toList();
  
  print(descriptions);
}

Key characteristics of the indexed property:

Using Extension Methods from the Collection Package

For scenarios requiring additional functionality, the Dart community provides the collection package, which includes extension methods such as mapIndexed and forEachIndexed.

First, add the dependency in pubspec.yaml:

dependencies:
  collection: ^1.18.0

Usage example:

import 'package:collection/collection.dart';

void main() {
  final numbers = [10, 20, 30, 40, 50];
  
  // Using mapIndexed for transformation
  final squaredWithIndex = numbers.mapIndexed((index, number) {
    return 'Square of index $index: ${number * number}';
  }).toList();
  
  // Using forEachIndexed for iteration
  numbers.forEachIndexed((index, number) {
    print('Number $index: $number');
  });
  
  print(squaredWithIndex);
}

Custom Extension Method Implementation

If projects have specific requirements, custom extension methods can be implemented. This approach offers maximum flexibility, allowing functionality customization according to particular business scenarios.

Complete custom implementation:

extension CustomIterableExtensions<E> on Iterable<E> {
  /// Indexed mapping method
  Iterable<T> mapIndexed<T>(T Function(E element, int index) mapper) {
    var currentIndex = 0;
    return map((element) => mapper(element, currentIndex++));
  }
  
  /// Indexed iteration method
  void forEachIndexed(void Function(E element, int index) action) {
    var currentIndex = 0;
    for (final element in this) {
      action(element, currentIndex++);
    }
  }
  
  /// Indexed filtering method
  Iterable<E> whereIndexed(bool Function(E element, int index) test) {
    var currentIndex = 0;
    return where((element) => test(element, currentIndex++));
  }
}

// Usage example
void main() {
  final colors = ['red', 'green', 'blue', 'yellow'];
  
  // Using custom mapIndexed
  final colorDescriptions = colors.mapIndexed((color, index) {
    return 'Color $index is $color';
  }).toList();
  
  // Using custom whereIndexed to filter even indices
  final evenIndexColors = colors.whereIndexed((color, index) {
    return index % 2 == 0;
  }).toList();
  
  print(colorDescriptions);
  print(evenIndexColors);
}

Performance Analysis and Best Practices

Different indexed iteration methods exhibit varying performance characteristics. Developers should select appropriate methods based on specific scenarios:

Performance Comparison:

Usage Recommendations:

Practical Application Scenarios

Indexed iteration finds extensive application in real-world projects:

Flutter UI Development:

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    final item = items[index];
    return ListTile(
      leading: CircleAvatar(
        child: Text('${index + 1}'),
      ),
      title: Text(item.title),
      subtitle: Text('Position: $index'),
    );
  },
)

Data Processing:

// Adding index identifiers to each element
final processedData = rawData.indexed.map(((int, dynamic) pair) {
  final (index, data) = pair;
  return {
    'id': index,
    'data': data,
    'timestamp': DateTime.now().add(Duration(seconds: index))
  };
}).toList();

Conclusion

Dart provides multiple powerful approaches for implementing indexed list iteration, each with its applicable scenarios and advantages. Developers should select appropriate solutions based on project-specific requirements, performance considerations, and code maintainability. As the Dart language continues to evolve, we anticipate the emergence of more elegant solutions that will further enhance development experience and code quality.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.