Debug School

rakesh kumar
rakesh kumar

Posted on

Dart/Flutter Map, HashMap Tutorial with Examples

  1. Introduction to Dart Map, HashMap, LinkedHashMap, SplayTreeMap
  2. How to create, initialize, add, get value, update, remove entriess in a Map
  3. Ways to iterate, search, filter, transform a Map in Dart/Flutter
  4. Way to sort a Map in Dart/Flutter A Dart Map is a collection of key-value pairs. It maps each key to exactly one value. We can iterate over a Map.
  • 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.

creating an instance using Map constructor (Map(), Map.from(), Map.of()) will return a 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>();
}
Enter fullscreen mode Exit fullscreen mode

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.");
}
Enter fullscreen mode Exit fullscreen mode

// Result: This is a LinkedHashMap.
In the code above, we specify the type of key-value pairs: .
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 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();
Enter fullscreen mode Exit fullscreen mode

Initialize a Map with values in Dart/Flutter

The examples show you how to:

initialize Map in simple way using {} (curly braces).

  1. create a Map with all key/value pairs of other Map using from(), of() constructor.
  2. create a new Map from the given keys and values using fromIterables().
  3. create Map in which keys and values are computed using fromIterable()
  4. 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);
Enter fullscreen mode Exit fullscreen mode

Remember that when we use Map or var, the type will always beLinkedHashMap.
`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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

`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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Dart/Flutter Map collection if and collection for
With the collection if and collection for, we can dynamically create maps using conditionals (if) and repetition (for).
Enter fullscreen mode Exit fullscreen mode
var mobile = true;
var myMap = {1: 'kotlin', 2: 'dart', if (mobile) 3: 'flutter'};
// {1: kotlin, 2: dart, 3: flutter}
var squareMap = {
  for (var i = 1; i <= 5; i++) i: i * i
};
// {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
var tringList = ['kotlin', 'dart', 'flutter', 'react'];
var i = 0;
var data = {for (var s in tringList) if (s.length > 5) i++: s};
// {0: kotlin, 1: flutter}
Add item to a Map in Dart/Flutter
There are 2 way to add an item (key-value pair) to a Map:

using square brackets []
calling putIfAbsent() method
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);
Enter fullscreen mode Exit fullscreen mode

`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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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:

  1. find the number of key/value pairs using .length getter.
  2. check if a Map is empty or not using .isEmpty or .isNotEmpty.
  3. get all keys or values with keys & values property.
  4. 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
Enter fullscreen mode Exit fullscreen mode

Dart/Flutter check existence of key/value in Map

We can check existence of:

  1. a key using containsKey() method.
  2. a value using containsValue() method.
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
Enter fullscreen mode Exit fullscreen mode

Remove objects from Map in Dart/Flutter

The examples show you how to:

  1. remove key-value pair by key using remove() method.
  2. remove all entries with condition using removeWhere() method.
  3. 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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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:

forEach() method.
entries property and forEach() method.
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} }');
});
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

`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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);


Enter fullscreen mode Exit fullscreen mode

Output:

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

Full Summary

Refrence

Top comments (0)