SkillByAIOpen interactive version →

Lesson 6 / 25

Lists, Sets, Maps and Iterables

Work with Dart collections and lazy Iterable operations.

Core collections

List<T> is an ordered, indexable collection (growable by default; List.unmodifiable and const lists are not). Set<T> holds unique elements (a LinkedHashSet preserving insertion order by default), and Map<K, V> maps keys to values (a LinkedHashMap by default, also insertion-ordered). All are generic, so the analyser checks element types. Most transformation methods live on Iterable and are lazy: map, where, expand, skip and take return iterables that compute elements only when iterated, so call toList() or toSet() when you need a concrete, reusable collection, and avoid iterating an expensive lazy chain several times. Other useful members: fold, reduce, any, every, firstWhere (with orElse), whereType<T>(), sorted via toList()..sort(...), asMap, indexed (Dart 3, yields index and element records), and for maps entries, putIfAbsent, update and map. Index access out of range throws a RangeError. The collection package adds helpers such as groupBy, firstWhereOrNull and deep equality.

Collections in everyday code

Lazy iterables, grouping by hand and map updates.

void main() {
  final orders = [
    (id: 'o1', city: 'Pune', total: 1200.0),
    (id: 'o2', city: 'Delhi', total: 300.0),
    (id: 'o3', city: 'Pune', total: 800.0),
  ];

  final bigIds = orders.where((o) => o.total >= 500).map((o) => o.id).toList();   // [o1, o3]
  final revenue = orders.fold<double>(0, (sum, o) => sum + o.total);            // 2300.0

  final byCity = <String, double>{};
  for (final o in orders) {
    byCity.update(o.city, (v) => v + o.total, ifAbsent: () => o.total);
  }
  print(byCity);                                 // {Pune: 2000.0, Delhi: 300.0}

  final cities = orders.map((o) => o.city).toSet();   // {Pune, Delhi}
  final sorted = orders.toList()..sort((a, b) => b.total.compareTo(a.total));

  for (final (index, o) in orders.indexed) {      // Dart 3 record destructuring
    print('$index: ${o.id}');
  }

  final first = orders.firstWhere((o) => o.city == 'Mumbai', orElse: () => orders.first);
}

map and where are lazy

orders.where(...) does nothing until you iterate it, and iterating twice runs the filter twice. Call toList() once if you will reuse the result, especially when the callback is expensive or has side effects.

Quick check: What does Iterable.where return?

  • A lazy Iterable whose elements are computed when iterated
  • A new List immediately
  • A Set
  • A Future
Answer

A lazy Iterable whose elements are computed when iterated — where and map are lazy; convert with toList() for a concrete collection.