close

flutter – get iteration index from list.map()

Dart writing computer programs is a language upgraded for building UIs utilized in the Flutter versatile structure. It consolidates the universe of OOP and practical. I am a major fanatic of useful programming, One of the issues in Dart I discovered exhausting and awkward is to compose the underlying List#map API. The List#map passes every component of the rundown to the callback without the record of the component. The full technique signature resembles this:

Iterable map(f(E element));

This is totally fine for certain cases. One of the situations, I discover it is helpful to have the option to get to the file is for instance:

  • You have 3 classifications in the rundown, and you realize the chose classification file. For each emphasis in the guide, you may have to contrast the record of every cycle with contrast and the chose list so you can do a custom UI for that chose class.

We should see the issue in code:

import 'package:flutter/material.dart';
class Category {
  String name;
  Category({@required this.name});
}
List<Category> categories = [
  Category(name: 'Electronics'),
  Category(name: 'Fashions'),
  Category(name: 'Home Appliances'),
];
class CategoryRenderingService {
  List<Category> categories;
  int selectedIndex = 0;
CategoryRenderingService({@required this.categories});
List<Widget> render() {
    return categories.map((category) {
      bool selected = categories.indexOf(category) == selectedIndex;
      
      TextStyle style = selected ? TextStyle(fontWeight: FontWeight.bold) : TextStyle(fontWeight: FontWeight.normal);
      return Text(category.name, style: style);
    }).toList();
  }
}

From the code above, to know whether a class is chosen, I need to look in the rundown utilizing the List#indexOf. There is nothing amiss with this except for I feel it is more normal to have the option to get to the current file of the emphasis and I need to maintain a strategic distance from the O(n2) unpredictability in the event that the quantity of things being referred to is sufficiently large to cause awful execution in your application.

In the wake of googling a piece I discovered this Stack Overflow question https://stackoverflow.com/questions/54990716/vacillate get-cycle record from-list-map. I don’t care for the methodology they tackle in there.

Subsequent to strolling through the official doc, I discovered List#asMap is by all accounts a very decent up-and-comer

Map asMap( )

Returns an unmodifiable Map perspective on this.

The guide utilizes the records of this rundown as keys and the comparing objects as qualities. The Map.keys Iterable repeats the files of this rundown in mathematical request

Solution

Since the List#asMap return a guide with ensured files in mathematical request when we summon Map#keys we utilize each to take care of the issue as follows.

List<Widget> render() {
    return categories.asMap().keys.toList().map((index) {
      bool selected = index == selectedIndex;
      
      TextStyle style = selected ? TextStyle(fontWeight: FontWeight.bold) : TextStyle(fontWeight: FontWeight.normal);
      return Text(categories[index].name, style: style);
    }).toList();
  }
}

Our outcome can be summed up this way:

List#asMap()#keys.toList()#map(T Function(int index));

I am attempting to make another API technique on first spot on the List.

# extensions/list_map_with_index_extension.dart
extension MapWithIndex<T> on List<T> {
  List<R> mapWithIndex<R>(R Function(T, int i) callback) {
    List<R> result = [];
    for (int i = 0; i < this.length; i++) {
      R item = callback(this[i], i);
      result.add(item);
    }
    return result;
  }
}

From the code above I add another strategy List#mapWithIndex. You can see the full use in the test underneath.

import 'package:flutter_test/flutter_test.dart';
import 'package:vtenh/extensions/list_map_with_index_extension.dart';

void main() {
  group('.mapWithIndex', () {
    test('return a new list from map value and index as original Int type', () {
      List<int> items = [20, 30, 40];
      List<int> result = items.mapWithIndex((value, index) => index * 2);

      expect(result.length, 3);
      expect(result[0], 0);
      expect(result[1], 2);
      expect(result[2], 4);
    });

    test('return a new list from map value and index as String type', () {
      List<int> items = [20, 30, 40];
      List<String> result = items.mapWithIndex((value, index) => "${index * 2}");

      expect(result.length, 3);
      expect(result[0], '0');
      expect(result[1], '2');
      expect(result[2], '4');
    });
  });
}

One issue with the above augmentation is that it restores a List. This API can make us confounded and cause irregularity with the implicit List#map API.

List#map strategy signature resembles this:

Iterable map(f(E element));

To make our API reliable with the dart worked in, how about we make another strategy to restore an Iterable rather than a List.

// lib/extensions/list_map_with_index_extension.dart
extension MapWithIndex<T> on List<T> {
  List<R> mapWithIndex<R>(R Function(T, int i) callback) {
    List<R> result = [];

    for (int i = 0; i < this.length; i++) {
      R item = callback(this[i], i);
      result.add(item);
    }
    return result;
  }

  Iterable<R> mapWithIndexIterable<R>(R Function(T, int i) callback) {
    return this.asMap().keys.toList().map((index) => callback(this[index], index));
  }
}

Below is the unit test

//test/extensions/list_map_with_index_extension_test.dart

import 'package:flutter_test/flutter_test.dart';
import 'package:vtenh/extensions/list_map_with_index_extension.dart';

void main() {
  group('.mapWithIndex', () {
    test('return a new list from map value and index as original Int type', () {
      List<int> items = [20, 30, 40];
      List<int> result = items.mapWithIndex((value, index) => index * 2);

      expect(result.length, 3);
      expect(result[0], 0);
      expect(result[1], 2);
      expect(result[2], 4);
    });

    test('return a new list from map value and index as String type', () {
      List<int> items = [20, 30, 40];
      List<String> result = items.mapWithIndex((value, index) => "${index * 2}");

      expect(result.length, 3);
      expect(result[0], '0');
      expect(result[1], '2');
      expect(result[2], '4');
    });
  });

  group('.mapWithIndexIterable', () {
    test('return a iterator from map value and index as original Int type', () {
      List<int> items = [20, 30, 40];
      Iterable<int> resultIterable = items.mapWithIndexIterable((value, index) => index * 2);
      List<int> result = resultIterable.toList();

      expect(resultIterable is Iterable<int>, true);
      expect(result.length, 3);
      expect(result[0], 0);
      expect(result[1], 2);
      expect(result[2], 4);
    });

    test('return a new list from map value and index as String type', () {
      List<int> items = [20, 30, 40];
      Iterable<String> resultIterable = items.mapWithIndexIterable((value, index) => "${index * 2}");
      List<String> result = resultIterable.toList();

      expect(resultIterable is Iterable<String>, true);
      expect(result.length, 3);
      expect(result[0], '0');
      expect(result[1], '2');
      expect(result[2], '4');
    });
  });
}

I am battling with the naming, in the event that you concoct a thought on the name I am glad to change.

Summery

It’s all About this issue. Hope all solution helped you a lot. Comment below Your thoughts and your queries. Also, Comment below which solution worked for you? Thank You.

Also Read

Leave a Comment