Maps in Dart

By Syncfusion®, Inc. · Last updated

How to store key-value pairs, read and change values by key, handle missing keys, and add, remove, search, loop over and transform maps.

What Is a Map?

Map = a collection of key-value pairs. You find each value by its key.

Key = the label you look up, like 'Maths'.

Value = what the key gives you, like 92.

For example:

  • subject → marks: 'Maths' → 92
  • roll number → name: 21 → 'Asha'
  • English word → Hindi word: 'water' → 'paani'

Simple lesson: a map links each key to one value, so you can find a value by its name instead of its position.

A Real-World Example

Think of a dictionary.

  • You do not read it from page 1 to find "elephant".
  • You look up the word (the key), and read its meaning (the value).
  • Every word appears once. A meaning can repeat.

A Dart map works the same way. Keys are unique, values do not have to be.

Every Run box on this page runs on the course's Dart runner in your browser.

Maps print with { } and a colon between each key and its value.

What You Will Learn

In this lesson, you will learn:

  1. What maps and key-value pairs are, and how to create them.
  2. How to read and change values by key, and handle missing keys.
  3. Map properties, like keys, values and entries.
  4. How to add, remove, search and loop over entries.
  5. How to transform maps, nest them, and make maps that never change.

Map Fundamentals

Creating Maps with Map Literals

Map literal = key: value pairs inside { }, separated by commas.

A map of subjects and marks

void main() {
  var marks = {'Maths': 92, 'Science': 85, 'English': 78};
  print(marks);
  print(marks.length);
}

Typed Maps

Typed map = Map<KeyType, ValueType>.

  • Map<String, int> = text keys, whole-number values.
  • Map<int, String> = number keys, text values.

Different key and value types

void main() {
  Map<int, String> rollCall = {1: 'Asha', 2: 'Ravi', 3: 'Priya'};
  Map<String, bool> present = {'Asha': true, 'Ravi': false};
  print(rollCall[2]);
  print(present['Ravi']);
}

Empty Maps

var marks = <String, int>{};
Map<String, int> scores = {};

{} with no type is a Map<dynamic, dynamic>. Add the types so Dart can check what goes in.

Simple lesson: write a map with { key: value }, and give it types like Map<String, int>.

Accessing and Updating Values

Press each button and watch the table:

Look at two things:

  • A new key adds a new row.
  • An existing key replaces its value. A key can never appear twice.

Accessing Values by Key

marks['Maths'] gives the value stored under the key 'Maths'.

Updating Values and Adding New Pairs

marks['Maths'] = 95;

  • If 'Maths' is already a key, its value is replaced.
  • If it is not, a new pair is added.

Reading, changing and adding

void main() {
  var marks = {'Maths': 92, 'Science': 85};
  print(marks['Maths']);
  marks['Maths'] = 95;
  marks['English'] = 78;
  print(marks);
}

Handling Missing Keys

A key that is not in the map gives null. It does not crash.

Missing keys give null

void main() {
  var marks = {'Maths': 92, 'Science': 85};
  print(marks['Art']);
  print(marks['Art'] ?? 0);
  print(marks.containsKey('Art'));
}
  • marks['Art'] has the type int?, because the key might be missing (see Null Safety).
  • Use ?? 0 for a default value.
  • Use containsKey to check first.

A map's keys are compared exactly. 'maths' and 'Maths' are two different keys.

Pick one spelling for your keys, and keep to it everywhere in your program.

Simple lesson: map[key] reads or writes one value, and a missing key gives null.

Map Properties

PropertyGives
lengthhow many pairs
isEmpty / isNotEmptywhether there are no pairs, or some
keysall the keys
valuesall the values
entriesall the pairs, as MapEntry objects

Keys, values and entries

void main() {
  var marks = {'Maths': 92, 'Science': 85, 'English': 78};
  print(marks.keys);
  print(marks.values);
  print(marks.entries);
  print(marks.keys.toList());
  print(marks.isNotEmpty);
}

MapEntry = one pair, with a .key and a .value.

keys, values and entries are Iterables, so they print with ( ). Use toList() for a list.

Simple lesson: keys and values give the two halves of a map, and entries gives the pairs.

Adding and Changing Elements

MethodWhat it does
addAll(other)copies every pair from another map
putIfAbsent(key, () => v)adds the pair only if the key is missing
update(key, (old) => new)changes one value using the old value
updateAll((k, v) => new)changes every value

Adding and changing pairs

void main() {
  var marks = {'Maths': 92, 'Science': 85};
  marks.addAll({'English': 78, 'Hindi': 81});
  marks.putIfAbsent('Maths', () => 50);
  marks.putIfAbsent('Art', () => 70);
  marks.update('Science', (old) => old + 5);
  print(marks);
  marks.updateAll((subject, mark) => mark + 2);
  print(marks);
}
  • putIfAbsent('Maths', ...) did nothing, because 'Maths' was already there.
  • update on a missing key crashes. Add ifAbsent: () => value to give a value instead.

Simple lesson: putIfAbsent adds only new keys, and update changes a value using its old value.

Removing Elements

  • remove(key) = removes the pair, and gives back its value (or null).
  • removeWhere((k, v) => test) = removes every pair that passes the test.
  • clear() = removes everything.

Removing pairs

void main() {
  var marks = {'Maths': 92, 'Science': 85, 'Art': 30, 'Music': 28};
  print(marks.remove('Science'));
  print(marks.remove('Dance'));
  marks.removeWhere((subject, mark) => mark < 35);
  print(marks);
  marks.clear();
  print(marks);
}

Simple lesson: remove a pair by its key, or remove many with a test.

Searching Maps

  • containsKey(k) = is this key in the map?
  • containsValue(v) = is this value in the map?

Searching keys and values

void main() {
  var marks = {'Maths': 92, 'Science': 85, 'English': 92};
  print(marks.containsKey('Maths'));
  print(marks.containsKey('Art'));
  print(marks.containsValue(85));
  print(marks.containsValue(100));
}

containsKey is very fast. containsValue has to check every value, so it is slower on big maps.

Simple lesson: look things up by key whenever you can, because keys are what maps are built for.

Iterating Maps

A map itself is not a list, so you loop over its keys, values or entries.

Four ways to go through a map

void main() {
  var marks = {'Maths': 92, 'Science': 85, 'English': 78};

  for (var subject in marks.keys) {
    print(subject);
  }

  for (var e in marks.entries) {
    print('${e.key} -> ${e.value}');
  }

  marks.forEach((subject, mark) {
    print('$subject: $mark');
  });

  var total = 0;
  for (var m in marks.values) {
    total += m;
  }
  print('Total: $total');
}

forEach on a map gives two values each time: the key and the value.

Counting with a Map

A map is perfect for counting things:

Count the votes

Simple lesson: loop over entries or use forEach to get each key with its value.

Map Transformations

map() and Creating New Maps

map((k, v) => MapEntry(newK, newV)) = a new map, made by changing every pair.

A new map from an old one

void main() {
  var marks = {'Maths': 92, 'Science': 85};
  var withGrace = marks.map((subject, mark) => MapEntry(subject, mark + 5));
  print(withGrace);
  var shout = marks.map((subject, mark) => MapEntry(subject.toUpperCase(), mark));
  print(shout);
  print(marks);
}

The old map is not changed.

Building a Map with for

A map built from a list

void main() {
  var names = ['Asha', 'Ravi', 'Priya'];
  var nameLengths = {for (var n in names) n: n.length};
  print(nameLengths);
}

cast()

cast<K, V>() = treats a map as a map with other types. It is mostly used with JSON data (see File Handling).

Simple lesson: map() with MapEntry builds a new map, and {for ...} builds one from a list.

Useful Map Features

Nested Maps

A value can be another map, or a list:

A map inside a map

void main() {
  Map<String, Map<String, int>> reportCards = {
    'Asha': {'Maths': 92, 'Science': 88},
    'Ravi': {'Maths': 75, 'Science': 81},
  };
  print(reportCards['Asha']!['Maths']);
  for (var student in reportCards.keys) {
    print('$student: ${reportCards[student]}');
  }
}

reportCards['Asha'] may be null in Dart's eyes, so ! says "this key is there" (see Null Safety).

Maps with Objects and Default Values

  • Values can be any type, including your own classes (see Classes).
  • For a default when a key is missing, use map[key] ?? defaultValue.

Simple lesson: maps can hold lists and other maps, so one variable can hold a whole report card.

Unmodifiable Maps

A const map cannot change

void main() {
  const passMarks = {'Maths': 35, 'Science': 35};
  print(passMarks['Maths']);
  passMarks['Art'] = 30;
}
  • const {...} = fixed before the program runs.
  • Map.unmodifiable(x) = a locked copy, made while it runs.

Easy way to remember

  • Find by position: List.
  • Find by name: Map.
  • Only unique values: Set.

Simple lesson: use const or Map.unmodifiable() when a map must never change.

TL;DR

  1. Map = key-value pairs: {'Maths': 92}. Keys are unique.

    • Typed: Map<String, int>. Empty: <String, int>{}.
  2. Read and write: map[key] and map[key] = value.

    • A missing key gives null. Use ?? or containsKey.
  3. Properties: length, keys, values, entries (MapEntry with .key and .value).
  4. Change: addAll, putIfAbsent, update, updateAll, remove, removeWhere, clear.
  5. Loop: over keys, values or entries, or forEach((k, v) ...).

    • Transform: map((k, v) => MapEntry(...)). Locked: const, Map.unmodifiable().

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
marks[0] for the first pairMaps have positionsMaps are found by keynull, or a type error.
marks['Art'] + 5Every key existsA missing key gives nullA null error. Use ?? 0.
for (var x in marks)A map is a listLoop over keys, values or entriesAn error.
update on a missing keyIt adds the keyIt crashes without ifAbsentKey not in map.
The same key twice in a literalBoth are keptThe last one winsOne pair goes missing.
marks.map((k, v) => v + 1)map returns valuesIt must return a MapEntryA type error.
Changing a const mapOnly the name is fixedA const map never changesAn Unsupported operation error.

Check Yourself

Exercises

What to Remember

  • A map stores key-value pairs. Keys are unique, values can repeat.
  • map[key] reads and writes. A missing key gives null, so use ?? or containsKey.
  • keys, values and entries let you loop over a map. forEach gives the key and value.
  • putIfAbsent adds only new keys, and update changes a value from its old value.
  • map() with MapEntry builds a new map, and const maps never change.

Next: Strings. You will learn to search, cut, change and build text.