Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 7

Working with Lists, Sets, and Maps

In the last chapter you learned how to write functions. Now we turn to collections — the containers Dart gives you for holding many values at once. Almost every real program stores groups of things: names in a list, unique tags in a set, settings in a map. This chapter walks through Dart's three cor
Level: GeneralLength: In depth3 min read

Read at another depth

Working with Lists, Sets, and Maps

In the last chapter you learned how to write functions. Now we turn to collections — the containers Dart gives you for holding many values at once. Almost every real program stores groups of things: names in a list, unique tags in a set, settings in a map. This chapter walks through Dart's three core collections in depth: List, Set, and Map.

A collection is an object whose job is to hold other objects and let you work with them as a group.

The three containers at a glance

TypeHoldsOrderingDuplicates?Fast lookup by
`List`an ordered sequenceinsertion orderyesposition (index)
`Set`distinct valuesusually insertion ordernovalue
`Map`key–value pairsinsertion order (usually)unique keys onlykey

Choose based on the question you need to answer quickly:

  • "Give me the third item" → List.
  • "Have I seen this value before?" → Set.
  • "What is the value for this key?" → Map.
Code example in dart
void main() {
  var fruits = ['apple', 'banana', 'cherry'];          // List
  var unique = {'apple', 'banana', 'apple'};           // Set: 'apple' appears once
  var ages = {'Ada': 36, 'Grace': 45};                 // Map
  print(fruits.length); // 3
  print(unique.length); // 2
  print(ages['Ada']);   // 36
}
A diagram showing a List as a numbered sequence of four boxes, a Set as a bag of four distinct values, and a Map as four keys each pointing to one value.
100%
The three core Dart collections and what they store
Show diagram source
graph LR
  subgraph List["List: ordered, indexed"]
    L0["0: 'a'"] --> L1["1: 'b'"] --> L2["2: 'c'"] --> L3["3: 'd'"]
  end
  subgraph Set["Set: unique values"]
    S1["'a'"] --- S2["'b'"] --- S3["'c'"] --- S4["'d'"]
  end
  subgraph Map["Map: key to value"]
    K1["'Ada'"] --> V1["36"]
    K2["'Grace'"] --> V2["45"]
  end

Lists: your ordered workhorse

A List keeps values in order, and each value has a numbered position called an index, starting at 0. You create one with square brackets.

Code example in dart
void main() {
  var todo = ['wash dishes', 'write code'];

  todo.add('walk dog');        // add at the end
  todo.insert(0, 'make coffee'); // insert at a position
  print(todo[0]);              // make coffee
  print(todo.last);            // walk dog
  print(todo.length);          // 4

  todo[1] = 'write Dart code'; // replace an item
  todo.removeAt(0);            // remove by position
  todo.remove('walk dog');     // remove by value
  print(todo);                 // [write Dart code, wash dishes]
}

Dart lists are growable: they expand as you add items. If you want a fixed-length list, you can create one explicitly, but in everyday code growable lists are the norm.

A list can also be marked constant with final or const. The difference matters:

  • final list = [...] — you cannot reassign the variable, but you can still change the list's contents.
  • const list = [...] — the list itself is frozen; adding or removing raises an error.

Sets: when every value must be unique

A Set stores each value at most once. Adding a duplicate does nothing. This makes sets perfect for questions like "which tags did this article get?" or "who has already signed up?"

Code example in dart
void main() {
  var seen = <String>{};
  for (var name in ['Ada', 'Alan', 'Ada', 'Grace']) {
    if (seen.add(name)) {   // add returns true if the value was new
      print('first time seeing $name');
    } else {
      print('already saw $name');
    }
  }
  print(seen.contains('Alan')); // true
  print(seen.length);           // 3
}

Sets also support math-like operations that answer comparison questions directly:

Code example in dart
void main() {
  var alice = {'dart', 'python', 'sql'};
  var bob = {'dart', 'rust'};

  print(alice.intersection(bob)); // {dart}       — both know
  print(alice.union(bob));        // {dart, python, sql, rust} — either knows
  print(alice.difference(bob));   // {python, sql} — only alice knows
}

Maps: key–value lookups

A Map associates each key with exactly one value. Keys are unique; values can repeat. Think of a real dictionary: you look up a word (key) and get its definition (value).

Code example in dart
void main() {
  var stock = {'apple': 5, 'banana': 0};

  stock['cherry'] = 12;         // add a new pair
  stock['apple'] = 4;           // update an existing value
  stock.remove('banana');

  print(stock.containsKey('apple')); // true
  print(stock.keys);                 // (apple, cherry)
  print(stock.values);               // (4, 12)
}

The missing-key trap

Here is the single most common Map surprise for newcomers. If you ask for a key that does not exist, Dart returns null rather than an error:

Code example in dart
void main() {
  var stock = {'apple': 5};
  int count = stock['pear']; // ERROR at runtime: null is not an int
}

With Dart's null safety (covered earlier in this tutorial), a plain int cannot be null, so this line fails. There are three safe fixes:

Code example in dart
void main() {
  var stock = {'apple': 5};

  // 1. Ask for a nullable type and handle null yourself.
  int? maybe = stock['pear'];
  print(maybe ?? 0);

  // 2. Provide a default right in the lookup.
  int count = stock['pear'] ?? 0;
  print(count); // 0

  // 3. Use putIfAbsent to insert a default if the key is missing.
  stock.putIfAbsent('pear', () => 0);
  print(stock); // {apple: 5, pear: 0}
}

The ?? operator ("if null") is your friend here: it returns the left value unless it is null, in which case it returns the right value.

Looping over collections

All three collections can be walked with a for-in loop:

Code example in dart
void main() {
  var fruits = ['apple', 'banana'];

  for (var fruit in fruits) {
    print(fruit);
  }

  var ages = {'Ada': 36, 'Grace': 45};
  ages.forEach((name, age) => print('$name is $age'));

  // Need the position too? Use an indexed loop.
  for (var i = 0; i < fruits.length; i++) {
    print('$i: ${fruits[i]}');
  }
}

Note what is not in these loops: you should not add or remove items from a list while looping over it. Dart may throw an error, and even when it does not, the results are confusing. Collect the changes and apply them after the loop.

Spreading and collecting

Two pieces of syntax make building collections easier. The spread operator ... inserts all the elements of one collection into another:

Code example in dart
void main() {
  var base = ['bread', 'milk'];
  var extras = ['eggs', 'cheese'];
  var cart = [...base, ...extras, 'jam'];
  print(cart); // [bread, milk, eggs, cheese, jam]

  // The null-aware spread ...? inserts nothing if the source is null.
  List<String>? coupons;
  var checkout = [...cart, ...?coupons];
  print(checkout.length);
}

There is also a collection if and collection for, which let you build lists conditionally or from another collection:

Code example in dart
void main() {
  var fancy = true;
  var order = ['coffee', if (fancy) 'whipped cream', for (var i in [1, 2]) 'shot $i'];
  print(order); // [coffee, whipped cream, shot 1, shot 2]
}

Choosing well: performance in plain terms

For an everyday mental model:

  • List indexing by position is instant, but checking whether a list contains a value scans the whole list.
  • Set and Map lookups check a value or key almost instantly, no matter how many items they hold.
  • If you find yourself calling list.contains(x) inside a loop, that loop is usually much faster with a Set instead.

Exercises

Exercise

You have a list of visitor names with duplicates: ['Ana', 'Bo', 'Ana', 'Cy', 'Bo']. How do you get a count of how many distinct people visited?

Show answer

Convert the list to a set and read its length: names.toSet().length gives 3. The set drops the duplicates, so its length counts distinct visitors.

Exercise

Write a lookup that safely reads prices['tea'] from a map and prints 0 if the key is missing.

Show answer

print(prices['tea'] ?? 0); — the ?? operator substitutes 0 when the map returns null for a missing key.

Exercise

You need a collection that answers "what is the email address for user ID 42?" as fast as possible. List, Set, or Map?

Show answer

A Map, keyed by the user ID. Maps give near-instant lookup by key, while a List would require scanning until you found the right entry.

Spotted a mistake, or code that does not work?

Report an issue

Chapter: Working with Lists, Sets, and Maps

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that