dart-flutter-map-complete-reference-feature-image

Dart/Flutter Map Tutorial with Examples

In this tutorial, we’ll show you many methods and functions to work with a Map in Dart (also in Flutter). You will know:

  • Introduction to Dart Map, HashMap, LinkedHashMap, SplayTreeMap
  • How to create, initialize, add, get value, update, remove entriess in a Map
  • Ways to iterate, search, filter, transform a Map in Dart/Flutter
  • Way to sort a Map in Dart/Flutter

Related Posts:
Dart/Flutter – Convert/Parse JSON string, array into Object, List
Dart/Flutter List Tutorial with Examples


Key points to note about Dart Map

A Dart Map is a collection of key-value pairs. It maps each key to exactly one value. We can iterate over a Map.

There are three types of map, depending in the order of iteration:

  • HashMap is unordered. The key-value pair coming later could be ordered first.
  • LinkedHashMap has predictable iteration order by the insertion order. The key-value pair coming later will be ordered later.
  • SplayTreeMap iterates the keys in sorted order. It is a self-balancing binary tree, frequently accessed elements will be moved more closely to the root of the tree.

By default, creating an instance using Map constructor (Map(), Map.from(), Map.of()) will return a LinkedHashMap.

So in the next sections, wherever we use Map, you can think about LinkedHashMap, and you can also replace Map with LinkedHashMap.

Create a new Map in Dart/Flutter

Using new keyword, we can create a new Map.
Don’t forget to import dart:collection library before using these syntax containing HashMap, LinkedHashMap, SplayTreeMap, also other code in the rest of this tutorial.

import 'dart:collection';

main() {
  HashMap hashMap = new HashMap<int, String>();
  LinkedHashMap linkedHashMap = new LinkedHashMap<int, String>();
  SplayTreeMap treeMap = new SplayTreeMap<int, String>();
}

With recent Dart version, we don’t need to use new keyword anymore.
For example, HashMap map = HashMap<int, String>() is accepted.

We can create a new LinkedHashMap using Map constructor like this.

Map map = Map<int, String>();
if (map is LinkedHashMap) {
  print("This is a LinkedHashMap.");
}

// Result: This is a LinkedHashMap.

In the code above, we specify the type of key-value pairs: <int, String>.
You can also declare a Map, LinkedHashMap, SplayTreeMap without setting the type for their keys and values. What does it mean? It will not constrain us to add a <int, String> pair into the Map.

These Maps now accept other types: <String, String>, <String, int>

Map map = Map();
HashMap map1 = HashMap();
LinkedHashMap map2 = LinkedHashMap();
SplayTreeMap map3 = SplayTreeMap();

Initialize a Map with values in Dart/Flutter

The examples show you how to:

  • initialize Map in simple way using {} (curly braces).
  • create a Map with all key/value pairs of other Map using from(), of() constructor.
  • create a new Map from the given keys and values using fromIterables().
  • create Map in which keys and values are computed using fromIterable()
  • create a ‘const’ Map using unmodifiable() constructor.
Map<String, int> map1 = {'zero': 0, 'one': 1, 'two': 2};
print(map1);

// not specify key-value type
Map map2 = {'zero': 0, 'I': 'one', 10: 'X'};
print(map2);

var map3 = {'zero': 0, 'I': 'one', 10: 'X'};
print(map3);

Remember that when we use Map or var, the type will always be LinkedHashMap.
Output:

{zero: 0, one: 1, two: 2}
{zero: 0, I: one, 10: X}
{zero: 0, I: one, 10: X}
Map<String, int> map1 = {'zero': 0, 'one': 1, 'two': 2};

Map map2 = Map.from(map1);
print(map2);

Map map3 = Map.of(map1);
print(map3);

Output:

{zero: 0, one: 1, two: 2}
{zero: 0, one: 1, two: 2}
List<String> letters = ['I', 'V', 'X'];
List<int> numbers = [1, 5, 10];

Map<String, int> map = Map.fromIterables(letters, numbers);
print(map);

Output:

{I: 1, V: 5, X: 10}
List<int> numbers = [1, 2, 3];

Map<String, int> map = Map.fromIterable(
  numbers,
  key: (k) => 'double ' + k.toString(),
  value: (v) => v * 2);

print(map);

Output:

{double 1: 2, double 2: 4, double 3: 6}
Map map = Map.unmodifiable({1: 'one', 2: 'two'});
print(map);
// {1: one, 2: two}

map[3] = 'three';

If you try to modify/add object to the unmodifiable Map, it will throw an error.

Unhandled exception:
Unsupported operation: Cannot modify unmodifiable map

Difference between Map.from() and Map.of

Look at the example below, we try to create two Map with wrong type:

Map<int, String> map = {1: 'one', 2: 'two'};

Map<String, String> map1 = Map.from(map); // runtime error
Map<String, String> map2 = Map.of(map);   // compilation error

You can see that:
Map.from(map) doesn’t cause any compilation error. When we run the statement, the error occurs:

Unhandled exception:
type 'int' is not a subtype of type 'String'

This is because of its prototype:

Map<K, V> Map.from(Map<dynamic, dynamic> other)

When we pass a Map<int, String> map to the function, it converts the key-value pair type into Map<dynamic, dynamic>.

Map.of(map) doesn’t do that thing, it keep the key-value pair type, so the compiler realizes the error before running the program.

Map<K, V> Map.of(Map<K, V> other)

Add item to a Map in Dart/Flutter

There are 2 way to add an item (key-value pair) to a Map:

Map map = {1: 'one', 2: 'two'};

map[3] = 'three';
print(map);

var threeValue = map.putIfAbsent(3, () => 'THREE');
print(map);
print(threeValue); // the value associated to key, if there is one

map.putIfAbsent(4, () => 'four');
print(map);

Output:

{1: one, 2: two, 3: three}
{1: one, 2: two, 3: three}
three
{1: one, 2: two, 3: three, 4: four}

You can add all key/value pairs of another Map to current Map using addAll() method.

Map map = {1: 'one', 2: 'two'};
map.addAll({3: 'three', 4: 'four', 5: 'five'});
print(map);

Output:

{1: one, 2: two, 3: three, 4: four, 5: five}

Map update value by key in Dart/Flutter

The examples show you how to update a Map value using:

  • square brackets []
  • update() method
  • update() method with ifAbsent to add a new object/entry if the input key is absent
Map map = {1: 'one', 2: 'two'};

map[1] = 'ONE';
print(map);

map.update(2, (v) {
  print('old value before update: ' + v);
  return 'TWO';
});
print(map);

map.update(3, (v) => 'THREE', ifAbsent: () => 'addedThree');
print(map);

Output:

{1: ONE, 2: two}
old value before update: two
{1: ONE, 2: TWO}
{1: ONE, 2: TWO, 3: addedThree}

Access items from Map in Dart/Flutter

The examples show you way to:

  • find the number of key/value pairs using .length getter.
  • check if a Map is empty or not using .isEmpty or .isNotEmpty.
  • get all keys or values with keys & values property.
  • get value of specified key in a Map or operator [].
Map map = {1: 'one', 2: 'two'};

print(map.length);      // 2

print(map.isEmpty);     // false
print(map.isNotEmpty);  // true

print(map.keys);        // (1, 2)
print(map.values);      // (one, two)

print(map[2]);          // two
print(map[3]);          // null

Dart/Flutter check existence of key/value in Map

We can check existence of:

Map map = {1: 'one', 2: 'two'};

print(map.containsKey(1));       // true
print(map.containsKey(3));       // false

print(map.containsValue('two')); // true
print(map.containsKey('three')); // false

Remove objects from Map in Dart/Flutter

The examples show you how to:

  • remove key-value pair by key using remove() method.
  • remove all entries with condition using removeWhere() method.
  • remove all entries from a Map using clear() method.
Map map = {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'};

map.remove(2);
print(map);

map.removeWhere((k, v) => v.startsWith('f'));
print(map);

map.clear();
print(map);

Output:

{1: one, 3: three, 4: four, 5: five}
{1: one, 3: three}
{}

Combine/merge multiple Maps in Dart/Flutter

The examples show how to combine Maps using:

  • addAll() method
  • from() and addAll() method
  • spread operator ... or null-aware spread operator ...? (from Dart 2.3)
Map map1 = {1: 'one', 2: 'two'};
Map map2 = {3: 'three'};
Map map3 = {4: 'four', 5: 'five'};

// addAll() method
var combinedMap1 = {}..addAll(map1)..addAll(map2)..addAll(map3);
print(combinedMap1);

// from() and addAll() method
var combinedMap2 = Map.from(map1)..addAll(map2)..addAll(map3);
print(combinedMap2);

// spread operator
var combinedMap3 = {...map1, ...map2, ...map3};
print(combinedMap3);

Output:

{1: one, 2: two, 3: three, 4: four, 5: five}

What if there is one of 3 Maps is null:

Map map1 = {1: 'one', 2: 'two'};
Map map2 = null;
Map map3 = {4: 'four', 5: 'five'};

If we combine these Maps using the methods above, the program will throw Exception:

NoSuchMethodError: The getter 'keys' was called on null.

To deal with it, we use null-aware spread operator ...?. The operator check null Map automatically with only one more ? symbol:

var combinedMap = {...?map1, ...?map2, ...?map3};
print(combinedMap);

Output:

{1: one, 2: two, 4: four, 5: five}

Iterate over Map in Dart/Flutter

The examples show you how to iterate over a Dart Map using:

Map map = {1: 'one', 2: 'two', 3: 'three'};

map.forEach((k, v) {
  print('{ key: $k, value: $v }');
});

map.entries.forEach((e) {
  print('{ key: ${e.key}, value: ${e.value} }');
});

Output:

{ key: 1, value: one }
{ key: 2, value: two }
{ key: 3, value: three }

We can iterate over keys or values using Map property and forEach() method.

map.keys.forEach((k) => print(k));
map.values.forEach((v) => print(v));

Output:

1
2
3
one
two
three

Dart/Flutter Map get key by value

Dart Map supports getting value by key, how about the opposite?
We can get key by a specified value using keys property and List firstWhere() method.

Map map = {1: 'one', 2: 'two', 3: 'three'};

var key = map.keys.firstWhere((k) => map[k] == 'two', orElse: () => null);
print(key);
// 2

Sort a Map in Dart/Flutter

The example shows you how to sort a Map by values using Map fromEntries() method and List sort() method.

Map map = {1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'};

var sortedMap = Map.fromEntries(
    map.entries.toList()
    ..sort((e1, e2) => e1.value.compareTo(e2.value)));
    
print(sortedMap);

Output:

{5: five, 4: four, 1: one, 3: three, 2: two}

For more details about sorting with List, please visit:
Sorting a List in Dart/Flutter

Map.map() method to transform a Map in Dart/Flutter

We can use map() method to get a new Map with all entries are transformed.

For example, the code below change keys and uppercase values of all entries.

Map map = {1: 'one', 2: 'two', 3: 'three'};

var transformedMap = map.map((k, v) {
  return MapEntry('($k)', v.toUpperCase());
});

print(transformedMap);

Output:

{(1): ONE, (2): TWO, (3): THREE}

Conclusion

In this Dart/Flutter tutorial, we’ve learned some important points of a Dart Map, how to create, initialize a Map, how to add, update and remove items from a Map, how to combine Maps, how to iterate over a Map, sort, transform a Map.

Happy learning! See you again!

Further Reading

One thought to “Dart/Flutter Map Tutorial with Examples”

Leave a Reply

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