Sets in Dart

By Syncfusion®, Inc. · Last updated

How to keep unique values with sets and set operations, and how to add and remove at both ends with queues from dart:collection.

What Is a Set?

Set = a collection where every value is unique. The same value can never appear twice.

For example:

  • the different subjects a student takes
  • the roll numbers of students who came to the library this week
  • the different words used in an essay

Adding a value that is already there does nothing.

Simple lesson: a set is like a list that refuses duplicates.

A Real-World Example

The library keeps a visitor book for the week.

  • Asha visits on Monday, Wednesday and Friday.
  • The librarian wants to know who visited, not how many times.
  • So each name is written once, even if the student came three times.

That list of names is a set.

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

Watch the curly braces { } in the output. They mean a set, not a list.

What You Will Learn

In this lesson, you will learn:

  1. What sets are, and how to create them.
  2. How to add, remove and search in a set.
  3. Set operations: union, intersection and difference.
  4. How to convert collections, and make sets that cannot change.
  5. How a Queue adds and removes items at both ends.

Set Fundamentals

Creating Sets with Set Literals

Set literal = values inside { }, separated by commas.

A set keeps one copy of each value

void main() {
  var subjects = {'Maths', 'Science', 'English', 'Maths'};
  print(subjects);
  print(subjects.length);
}

'Maths' was written twice, but the set keeps it once. The length is 3.

Typed Sets and Empty Sets

  • Typed set: Set<String> houses = {'Red', 'Blue'};
  • Empty set: var visitors = <String>{};

{} on its own makes an empty Map, not a set (see Maps).

For an empty set, write the type: <String>{}, or Set<String> visitors = {};.

Unique Values

  • A set checks every new value with ==.
  • If an equal value is already inside, the new one is not added.
  • The order you added items in is kept.

Simple lesson: write a set with { }, and Dart keeps just one copy of each value.

Set Properties

PropertyGives
lengthhow many items
isEmpty / isNotEmptywhether there are no items, or some
first / lastthe first or last item added

Set properties

void main() {
  var houses = {'Red', 'Blue', 'Green'};
  print(houses.length);
  print(houses.isEmpty);
  print(houses.isNotEmpty);
  print(houses.first);
  print(houses.last);
}

A set has no index. You cannot write houses[0]. Use first, last or a loop instead.

Simple lesson: a set has a length, a first and a last item, but no index.

Adding and Removing Elements

Adding Elements

  • add(x) = adds x, and gives true if it was new, false if it was already there.
  • addAll([...]) = adds many values at once.

add() gives true or false

Removing Elements

  • remove(x) = removes x, and gives true if it was there.
  • removeWhere(test) = removes every item that passes the test.
  • clear() = removes everything.

Removing from a set

void main() {
  var clubs = {'Chess', 'Music', 'Art', 'Coding', 'Dance'};
  print(clubs.remove('Art'));
  print(clubs.remove('Cricket'));
  clubs.removeWhere((c) => c.startsWith('D'));
  print(clubs);
  clubs.clear();
  print(clubs);
}

Simple lesson: add and remove tell you whether they changed the set, with true or false.

Searching Elements

  • contains(x) = true if x is in the set.
  • lookup(x) = gives back the item in the set that equals x, or null.

Is this student in the chess club?

void main() {
  var chess = {'Asha', 'Ravi', 'Priya'};
  print(chess.contains('Ravi'));
  print(chess.contains('Kiran'));
  print(chess.lookup('Priya'));
  print(chess.lookup('Kiran'));
}

contains on a set is very fast, even with thousands of items. A list has to check item by item.

Simple lesson: use contains to check membership. It is the main reason to use a set.

Set Operations

Pick an operation and compare the two clubs:

  • union(other) = everything in either set.
  • intersection(other) = only what is in both sets.
  • difference(other) = what is in this set but not in the other.

Comparing two clubs

void main() {
  var chess = {'Asha', 'Ravi', 'Priya', 'Kiran'};
  var music = {'Priya', 'Kiran', 'Meena', 'Imran'};
  print(chess.union(music));
  print(chess.intersection(music));
  print(chess.difference(music));
  print(music.difference(chess));
}

chess.difference(music) and music.difference(chess) are different. Order matters.

These come from maths class: union (∪), intersection (∩) and difference (−).

Simple lesson: union joins, intersection keeps the shared part, and difference takes away.

Iterating Sets

Sets work with the same loops as lists (see Loops):

Three ways to visit every item

void main() {
  var houses = {'Red', 'Blue', 'Green'};

  for (var h in houses) {
    print('$h House');
  }

  houses.forEach((h) => print(h.toUpperCase()));

  var list = houses.toList();
  for (var i = 0; i < list.length; i++) {
    print('$i: ${list[i]}');
  }
}

A set has no index, so a counted for loop needs toList() first.

Functional Operations

where, map, any and every work just like on lists (see Working with Iterables):

where, map, any and every on a set

void main() {
  var marks = {45, 82, 91, 30, 67};
  print(marks.where((m) => m >= 50).toSet());
  print(marks.map((m) => m + 5).toSet());
  print(marks.any((m) => m < 35));
  print(marks.every((m) => m > 20));
}

Simple lesson: loop over a set with for-in, and use where and map just like with lists.

Converting Collections

Removing Duplicates

A very common trick: turn a list into a set, and back into a list.

Remove duplicate names

void main() {
  var signUps = ['Asha', 'Ravi', 'Asha', 'Priya', 'Ravi', 'Asha'];
  var unique = signUps.toSet();
  print(unique);
  var cleanList = unique.toList();
  print(cleanList);
  print('${signUps.length} sign-ups, ${cleanList.length} students');
}
  • list.toSet() = a set with the duplicates gone.
  • set.toList() = a list, so you can use indexes and sort again.
  • Set.from(list) = another way to make a set from a list.

Simple lesson: toSet() removes duplicates, and toList() turns a set back into a list.

Unmodifiable Sets

Unmodifiable set = a set that can never change.

  • const {...} = fixed while you write the code.
  • Set.unmodifiable(x) = a locked copy, made while the program runs.

A const set cannot change

void main() {
  const weekend = {'Saturday', 'Sunday'};
  print(weekend.contains('Sunday'));
  weekend.add('Friday');
}

Adding to it fails with an Unsupported operation error.

Easy way to remember

  • Order and duplicates matter: List.
  • Only "is it in there?" matters: Set.
  • Need to remove duplicates: list.toSet().toList().

Simple lesson: use const or Set.unmodifiable() when a set must never change.

What Is a Queue?

Queue = a collection where items join at one end and leave from the other.

FIFO (First In, First Out) = the first item added is the first item taken out.

For example:

  • students waiting at the canteen counter
  • print jobs waiting for the school printer
  • messages waiting to be sent

A queue can also add and remove at both ends, when you need to.

Simple lesson: a queue is a line: join at the back, leave from the front.

A Real-World Example

At the canteen, students stand in a line.

  • A new student joins at the back.
  • The shopkeeper serves the student at the front.
  • Nobody in the middle is served first.

That is FIFO. Try it:

A queue prints with { }, like a set, but it keeps duplicates and order.

Queue Fundamentals

Importing dart:collection

Queue is not built in like List. It lives in the dart:collection library (see Libraries).

import 'dart:collection';

Creating Queues

Your first queue

import 'dart:collection';

void main() {
  var line = Queue<String>();
  line.add('Asha');
  line.add('Ravi');
  line.add('Priya');
  print(line);

  var printJobs = Queue.of(['Report', 'Timetable']);
  print(printJobs);
}
  • Queue<String>() = an empty queue of text.
  • Queue.of([...]) = a queue that starts with these items.

Queue vs List

QuestionListQueue
Read any item by index?Yes, list[3]No, use elementAt(3) (slow)
Remove from the front?Slow on big listsFast
Add to the front?Slow on big listsFast
Best foritems you look up by positionitems you process in order

A list has to shift every item when you remove the first one. A queue does not.

Simple lesson: use a queue when you add at one end and remove from the other, again and again.

Adding Elements

MethodWhat it does
add(x)joins at the back
addLast(x)joins at the back (same as add)
addFirst(x)goes straight to the front
addAll([...])many items join at the back

Joining the line

import 'dart:collection';

void main() {
  var line = Queue<String>();
  line.add('Asha');
  line.addLast('Ravi');
  line.addAll(['Priya', 'Kiran']);
  line.addFirst('Teacher');
  print(line);
}

addFirst lets someone skip to the front, like a teacher at the canteen.

Simple lesson: add joins at the back, and addFirst jumps to the front.

Accessing Elements

  • first = the item at the front, the next one to leave.
  • last = the item at the back.
  • elementAt(i) = the item at position i. It walks the queue, so avoid it in big queues.

Who is at the front?

import 'dart:collection';

void main() {
  var line = Queue.of(['Asha', 'Ravi', 'Priya']);
  print('Next to be served: ${line.first}');
  print('Last in line: ${line.last}');
  print('Second in line: ${line.elementAt(1)}');
}

Reading first does not remove the item. It only looks.

Simple lesson: first peeks at the front, and last peeks at the back.

Removing Elements

MethodWhat it does
removeFirst()takes the front item out, and gives it back
removeLast()takes the back item out, and gives it back
remove(x)takes out the first x found, gives true or false
clear()empties the queue

Serving the canteen line

An Empty Queue

Nobody is left to serve

import 'dart:collection';

void main() {
  var line = Queue<String>();
  print(line.isEmpty);
  line.removeFirst();
}

The error is Bad state: No element. Check isEmpty or isNotEmpty before removing.

Simple lesson: removeFirst serves the front item, so always check the queue is not empty first.

Queue Properties

  • length = how many items are waiting.
  • isEmpty = true when nobody is waiting.
  • isNotEmpty = true when at least one item is waiting.

Serve everyone, one by one

import 'dart:collection';

void main() {
  var line = Queue.of(['Asha', 'Ravi', 'Priya']);
  print('${line.length} waiting');
  while (line.isNotEmpty) {
    var student = line.removeFirst();
    print('Serving $student, ${line.length} left');
  }
  print(line.isEmpty);
}

This while (queue.isNotEmpty) pattern is how most queues are processed.

Simple lesson: loop with while (queue.isNotEmpty) and removeFirst() to process every item in order.

Iterating Queues

You can also loop over a queue without removing anything:

Looking at the whole line

import 'dart:collection';

void main() {
  var line = Queue.of(['Asha', 'Ravi', 'Priya']);

  for (var s in line) {
    print('Waiting: $s');
  }

  line.forEach((s) => print(s.toUpperCase()));

  var asList = line.toList();
  for (var i = 0; i < asList.length; i++) {
    print('${i + 1}. ${asList[i]}');
  }
}
  • for-in and forEach() visit items from front to back.
  • A queue has no index, so a counted loop needs toList() first.

Do not add or remove items inside a for-in loop over the same queue.

Dart stops with a ConcurrentModificationError. Use while (isNotEmpty) with removeFirst() instead.

Simple lesson: for-in looks at every item, and removeFirst in a while loop processes them.

Common Use Cases

Where queues are used

Breadth-First Search

Breadth-first search = visit the start, then everything one step away, then everything two steps away, and so on.

Who gets the school notice, level by level?

import 'dart:collection';

void main() {
  var tellsTo = {
    'Principal': ['Teacher A', 'Teacher B'],
    'Teacher A': ['Asha', 'Ravi'],
    'Teacher B': ['Priya'],
  };
  var queue = Queue.of(['Principal']);
  while (queue.isNotEmpty) {
    var person = queue.removeFirst();
    print(person);
    queue.addAll(tellsTo[person] ?? []);
  }
}

The principal is first, then both teachers, then the students. A queue keeps that order.

Easy way to remember

  • Queue = canteen line: first in, first out.
  • add = join the back. removeFirst = serve the front.
  • Need an index? Use a List instead.

Simple lesson: use a queue whenever things must be handled in the order they arrived.

TL;DR

  1. Set = unique values: {'Asha', 'Ravi'}. Empty: <String>{}.
  2. add returns false for a duplicate. contains is fast.
  3. union, intersection, difference compare two sets.
  4. list.toSet() removes duplicates. Set.unmodifiable cannot change.
  5. Queue (from dart:collection): addFirst, addLast, removeFirst, removeLast.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
var s = {}; for a set{} is an empty set{} is an empty MapSet methods like add behave like a Map's.
houses[0]Sets have indexesUse first, or toList() firstAn error.
Expecting duplicates to be countedA set counts every addA set keeps one copylength is smaller than expected.
Mixing up difference ordera.difference(b) is the same as b.difference(a)The order mattersThe wrong students are listed.
Ignoring add's resultadd always addsIt gives false for a duplicateYou miss that a value was already there.
Changing a const setconst only fixes the nameA const set never changesAn Unsupported operation error.
No import 'dart:collection';Queue is built inIt lives in dart:collectionUndefined name 'Queue'.
queue[0]Queues have indexesUse first, or elementAtAn error.
removeFirst() on an empty queueIt gives nullIt crashesBad state: No element.
Changing the queue in its for-inThe loop sees the changeUse while (isNotEmpty)ConcurrentModificationError.
A queue for lookups by positionQueues are like listsUse a List for indexesSlow code.
Reading first to take the itemfirst removes itfirst only looksThe item is processed twice.

Check Yourself

Exercises

What to Remember

  • A set never holds the same value twice.
  • {} alone is a map, so write <Type>{} for an empty set.
  • Use union, intersection and difference to compare groups.
  • toSet() is the quickest way to remove duplicates from a list.
  • A Queue is the right tool when you add and remove at both ends.

Next: Maps. You will learn to store pairs, like a subject and its marks, and find any value by its key.