How to Get the Index in the Map or forEach Function in Flutter

When working with lists in Flutter, you might need to get the index of the elements you are looping over. This can be useful if you want to perform actions on the elements that have a certain index. In this post, we will go over different methods to get the index in the map or forEach function in Flutter. We will cover built-in methods, extensions, and even a package to get the index.

Get the Index Using the asMap Function

The asMap function in Dart is a built-in method that transforms a List into a Map. It assigns the current index of each item as the corresponding key. In the examples below, we use this function together with the map and forEach functions to change items in the list based on their index.

Using Map

The current items list only has booleans that are false. We want to loop over them and if the element’s index is 1 we want to set the value to true.

void main() {
  List<bool> items = [false, false, false];

  List<bool> newItems = items.asMap().entries.map((MapEntry<int, bool> entry) {
    return entry.key == 1;
  }).toList();

  print(newItems);
}

In the above example, we use the asMap() function on our items list to transform the list so that we can access the entries. Once we have the entries we can map over them and for every entry we can use the key as the index. Once the entry.key is equal to 1 we will return true.

By using the map function we created a new list instead of modifying the existing one. If you want to modify the new list, you could use the forEach function instead.

Using forEach

The forEach implementation is very similar.

void main() {
  List<bool> items = [false, false, false];

  items.asMap().entries.forEach((MapEntry<int, bool> entry) {
    items[entry.key] = entry.key == 1;
  });

  print(items);
}

We also call the asMap function followed by the entries so that we can get the index in the forEach function. In the forEach function, we assign a new value to every item in the list. When the index is equal to 1 the value will be true.

Get the Index in the Map or ForEach function Using the Indexed Getter in Flutter

An easier approach to get the index in the map or forEach function in Flutter is to use the indexed getter. The indexed getter enables access to the index when we chain it with the map or forEach function.

Using Map

In the below code, we call the indexed getter on the list and use the map function to loop over it.

void main() {
  List<bool> items = [false, false, false];

  List<bool> newItems = items.indexed.map(((int, bool) item) {
    final (index, value) = item;

    return index == 1;
  }).toList();

  print(newItems);
}

Because we are using the indexed getter we can both access the index and value of the item inside the map. As you can see on line 5 we destructure the item into 2 variables. Afterward, we only use the index to ensure that we return true when the index is equal to 1.

Using forEach

The forEach approach is very similar, but we are using a for loop to avoid passing Function literals to the forEach function.

void main() {
  List<bool> items = [false, false, false];

  for (final (int, bool) item in items.indexed) {
    final index = item.$1;

    items[index] = index == 1;
  }

  print(items);
}

Inside the for loop, we are using the $1 selector to select the index from the item. This is an alternative approach to destructuring the item as we did in the map function. One is not better than the other, but I think the first approach is easier to read.

Like before we are also modifying the existing items list and ensuring that the item with index 1 is set to true.

Get the Index Using the List.generate function

Instead of using the map or forEach function we can also use the List.generate function. The List.generate function will create a new list and accepts a callback that has access to the index.

void main() {
  List<bool> items = [false, false, false];

  List<bool> newItems = List.generate(items.length, (int index) {
    return index == 1;
  });

  print(newItems);
}

Inside the callback, we ensure to return true when the index is equal to 1.

Use the Collection Package to Get the Index in the Map or ForEach function in Flutter

Instead of using the built-in functions, we can also choose to use the Collection package. This package contains utility functions and classes to make working with collections easier. The functions we are interested in from this package are mapIndexed and forEachIndexed.

Install the Collection package

First, we need to install the Collection package into our project. The installation process is simple. Just execute the following command:

flutter pub add collection

Once the command is executed, make sure to check your pubspec.yaml file for the added dependencies. You should see the Collection package included in the dependencies section, like this:

dependencies:
  collection: ^1.18.0

Use the mapIndexed function

The mapIndexed function can be directly called on the items list.

import 'package:collection/collection.dart';

void main() {
  List<bool> items = [false, false, false];

  List<bool> newItems = items.mapIndexed((int index, bool item) {
    return index == 1;
  }).toList();

  print(newItems);
}

In this code snippet, we call the mapIndexed function on the items list. Inside the function, we have access to the index and item. We return true or false based on the index being 1. We call the toList function to convert the map back into a list.

Use the forEachIndexed function

The forEachIndexed function can also be directly called on the list.

import 'package:collection/collection.dart';

void main() {
  List<bool> items = [false, false, false];

  items.forEachIndexed((int index, bool item) {
    items[index] = index == 1;
  });

  print(items);
}

Using the forEachIndexed function we can easily access the index for each item in the list as we did with the mapIndexed function.

So far, these functions represent the simplest ways to achieve our goal. Yet, adding an entire package just for two functions might be a bit much. Luckily, there is one more approach we can take.

Create Extensions to Get the Index in Map or ForEach Function in Flutter

Instead of using the Collection package to use the mapIndexed and forEachIndexed functions, we can create them ourselves using extensions.

In short, extensions in Dart are a way to add new functionality to existing classes without modifying their original code. They allow us to define new functions or properties for existing classes, making it easier to organize and extend our code without directly changing the class itself.

Create the IterableMapIndexed Extension

The extension keyword introduces an extension named IterableMapIndexed. This extension can be attached to any type that follows the iterable pattern, like lists or sets.

extension IterableMapIndexed<T> on Iterable<T> {
  Iterable<R> mapIndexed<R>(R Function(int index, T element) convert) sync* {
    int index = 0;

    for (final element in this) {
      yield convert(index++, element);
    }
  }
}

void main() {
  List<bool> items = [false, false, false];

  List<bool> newItems = items.mapIndexed((int index, bool item) {
    return index == 1;
  }).toList();

  print(newItems);
}

Inside this extension, we define the mapIndexed function. This function takes another function called convert as input. The convert function has two parameters: an int that stands for the index and a general type T that represents an element. It returns an outcome of another type R.

The sync* keyword is used to show that the function works as a synchronous generator. This means it can provide multiple values one after another.

We create a variable named index and set it 0.

We then use a for-in to go through each element within the iterable. For each element, we run the convert function. This function gets the current index and the element as inputs. The outcome is passed using the yield keyword, which can give you one value at a time. After that, the index gets increased by one.

Now inside our main function, we can use the mapIndexed function without using the Collection package.

Create the IterableForEachIndexed Extension

The same can be done for the forEachIndexed function.

extension IterableForEachIndexed<T> on Iterable<T> {
  void forEachIndexed(void Function(int index, T element) action) {
    int index = 0;

    forEach((element) => action(index++, element));
  }
}

void main() {
  List<bool> items = [false, false, false];

  items.forEachIndexed((int index, bool item) {
    items[index] = index == 1;
  });

  print(items);
}

The forEachIndexed function accepts another function called action as input. The action function has two parameters: an int that stands for the index and a general type T that stands for an element.

Like the mapIndexed function we create an index variable and set it to 0.

Then we loop over the iterable using a forEach function and call the action function for each element.

Now we can also use the forEachIndexed function without using the collection package.

Conclusion

As you have seen, getting the index while using the map and forEach functions in Flutter can be achieved in a lot of different ways. Either by using built-in methods, using external packages, or creating extensions. Some approaches are easier than others, and some might not work for every use case. However, you should now have enough knowledge to choose the right approach.

Tijn van den Eijnde
Tijn van den Eijnde
Articles: 40

Leave a Reply

Your email address will not be published. Required fields are marked *