List of map in Dart

Iterable map[
]

Returns a new lazy Iterable with elements that are created by calling f on each element of this Iterable in iteration order.

This method returns a view of the mapped elements. As long as the returned Iterable is not iterated over, the supplied function f will not be invoked. The transformed elements will not be cached. Iterating multiple times over the the returned Iterable will invoke the supplied function f multiple times on the same element.

Methods on the returned iterable are allowed to omit calling f on any element where the result isn't needed. For example, elementAt may call f only once.

/** * Returns a new lazy [Iterable] with elements that are created by * calling `f` on each element of this `Iterable` in iteration order. * * This method returns a view of the mapped elements. As long as the * returned [Iterable] is not iterated over, the supplied function [f] will * not be invoked. The transformed elements will not be cached. Iterating * multiple times over the the returned [Iterable] will invoke the supplied * function [f] multiple times on the same element. * * Methods on the returned iterable are allowed to omit calling `f` * on any element where the result isn't needed. * For example, [elementAt] may call `f` only once. */ Iterable map[f[E element]];

Dart programming is a language optimized for building user interfaces used in the Flutter mobile framework. It combines the world of OOP and functional. I am a big fan of functional programming, One of the problems in Dart I found boring and inconvenient is to write the built-in List#map API. The List#map passes each element of the list to the callback without the index of the element. The full method signature looks like this:

This is perfectly fine for some cases. One of the scenarios, I find it is useful to be able to access the index is for example:

  • You have 3 categories in the list, and you know the selected category index. For every iteration in the map, you might need to compare the index of each iteration to compare with the selected index so you can do a custom UI for that selected category.

Let’s see the problem in code:

From the code above, in order to know if a category is selected, I have to search in the list using the List#indexOf. There is nothing wrong with this but I feel it is more natural to be able to access the current index of the iteration and I want to avoid the O[n2] complexity in case the number of items in question is big enough to cause bad performance in your app.

After googling a bit I found this Stack Overflow question //stackoverflow.com/questions/54990716/flutter-get-iteration-index-from-list-map. I don’t like the approach they solve in there.

After walking through the official doc, I found List#asMap seems to be a pretty good candidate

Map asMap[ ]

Returns an unmodifiable Map view of this.

The map uses the indices of this list as keys and the corresponding objects as values. The Map.keys Iterable iterates the indices of this list in numerical order

Solution

Since the List#asMap return a map with guaranteed indices in numerical order when we invoke Map#keys we use each to solve the problem as follows.

Our end result can be summarized like this:

Ruby and Javascript are one of my favorites programming languages, both provide powerful closures, functional features, and metaprogramming. I would like to dig a little bit further to customize the language, I found this extension feature in dart similar to metaprogramming in Ruby. You can find the explanation from the official dart website here: //dart.dev/guides/language/extension-methods.

I am trying to create another API method on top of the List.

From the code above I add a new method List#mapWithIndex. You can see the full usage in the test below.

One problem with the above extension is that it returns a List. This API can make us confused and cause inconsistency with the built-in List#map API.

List#map method signature looks like this:

To make our API consistent with the dart built-in, let’s create a new method to return an Iterable instead of a List.

Below is the unit test

I am struggling with the naming, if you come up with an idea on the name I am happy to change.

Conclusion

Writing extension is fun. With a functional approach, the code is much nicer and cleaner. From the above example, it opens whole lots of opportunity to extend further for other methods as well, for example, you might be interested in creating a new extension method List#forEachWithIndex.

You might not need to write a custom extension method, as the dart programming is powerful enough to help you solve problems, after all, it is just an opinionated way.

The following snippet demonstrates how to access the iteration index when using List.map. It is a common need in Flutter when looping over or mapping a list of values to widgets.

Problem

Unlike JavaScript, one cannot simply access the index of a list during a List.map operation in Dart.

List myList = ['a', 'b', 'c']; myList.map[ [val, index] { // This does not work! // Which index am I on? }]

Solutions

There are several ways to access the index when looping over a List.

Use Map Entries

Convert the List to a Map, then map the entries containing the key/value pairs. Each key in the map is the index of the original list.

myList.asMap[].entries.map[[entry] { int idx = entry.key; String val = entry.value; return something; }

Generate a Fixed Range List

If you are looping over many lists that have a fixed length, it may be more efficient to generate a single list once. For example, the we create a ranged list that is the same length as the original, i.e. [0, 1, 2, ..., n]

final List fixedList = Iterable.generate[myList.length].toList[]; fixedList.map[[idx] { String val = myList[idx]; return something; }

Grab the Index of Unique Values

You can access the index of a specific value by searching for it with List.indexOf, which returns the index of the first match. This approach is most predictable when all values are unique. A Set can ensure uniqueness throughout the list.

final List uniqueList = Set.from[myList].toList[]; uniqueList.map[[val] { String idx = uniqueList.indexOf[val]; return something; }

Video liên quan

Chủ Đề