Watch the video (10 min)
On this page23 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. What Is a Set?
  5. 2. Giving a Set a Type
  6. 3. {} on Its Own Is a Map, Not a Set
  7. 4. add — and the bool It Returns
  8. 5. addAll — Many Values at Once
  9. 6. Order: Insertion Order, but No Indexes
  10. 7. remove — Also Returns a bool
  11. 8. contains, length and isEmpty
  12. 9. Looping Over a Set
  13. 10. List → Set → List: Removing Duplicates
  14. 11. A Real-World Example
  15. Code Examples
  16. Common Beginner Mistakes
  17. Best Practices
  18. Mini Challenge
  19. Practice Questions
  20. Practice Answers
  21. Quick Revision
  22. Key Takeaways
  23. What's Next?

Lecture 47 — Sets

Category8 — Sets & Maps
Lecture047 of 140
Estimated video length10 min
TargetDart 3.12.2
LevelBeginner

A list happily stores 'Ali' twice, so "who came?" needs extra checking. A set keeps every value once — duplicates are simply ignored.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways

Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.


Prerequisites

Students should already understand, from Lectures 001–046:

  • final variables (Lecture 006) and for-in loops (Lecture 027)
  • the conditional expression ? : (Lecture 023)
  • creating lists, List<int>, length, and isEmpty (Lecture 039)
  • add, remove and the ConcurrentModificationError (Lecture 041)
  • contains (Lecture 042)

Connection With Previous Lectures

Lists keep everything you give them, including repeats:

dart
void main() {
  var visitors = ['Ali', 'Sara', 'Ali', 'Zayan', 'Sara'];
  print(visitors.length);
}
output
5

Five entries, but only three people visited. To count people, you would have to check every name before adding it, or clean the list afterwards. In Lecture 034 we also saw that braces after => accidentally make "a Set". Today we meet that collection on purpose: it does the duplicate-checking for you.


Learning Objectives

By the end of this lecture you will be able to:

  • Explain what a set is and how it differs from a list
  • Create sets with {} literals and Set<T> types
  • Create an empty set correctly, knowing that {} alone is a Map
  • Use add and read the true / false it returns
  • Use remove, contains, length, and isEmpty
  • Loop over a set with for-in
  • Remove duplicates from a list with toSet() and turn the result back with toList()
  • Recognize the errors Dart gives for common set mistakes

1. What Is a Set?

A set is a collection where every value appears at most once.

Analogy — think of a sticker album. Each sticker has one slot. If you already own the Lion sticker, a second Lion doesn't get a new slot; the album stays the same.

Sets are written with curly braces instead of square brackets:

dart
void main() {
  var names = {'Ali', 'Sara', 'Zayan'};
  print(names);
  print(names.length);
}
output
{Ali, Sara, Zayan}
3

Dart prints a set with braces too, so you can tell it from a list at a glance.


2. Giving a Set a Type

Like List<int>, a set has an element type: Set<int> means "a set of int".

dart
void main() {
  Set<int> marks = {85, 92, 78};
  Set<String> cities = {'Karachi', 'Lahore'};
  print(marks);
  print(cities);
}
output
{85, 92, 78}
{Karachi, Lahore}

With var, Dart infers the type from the values, exactly as for lists. Every element is checked: Set<int> marks = {80, 'ninety'}; is rejected before the program runs.


3. {} on Its Own Is a Map, Not a Set

Curly braces are shared with another collection, the Map (Lecture 049). When the braces are empty, Dart cannot see any elements, so it picks Map:

dart
void main() {
  var visitors = {};
  print(visitors.runtimeType);
}
output
_Map<dynamic, dynamic>

runtimeType (Lecture 010) reveals the truth — it is a Map, and a Map has no add:

dart
void main() {
  var visitors = {};
  visitors.add('Ali'); // ✗ visitors is a Map
}
output
Error: The method 'add' isn't defined for the type 'Map<dynamic, dynamic>'.

To make an empty set, give Dart the type — either on the variable or in front of the braces:

dart
void main() {
  Set<String> visitors = {};
  var guests = <String>{};
  visitors.add('Ali');
  guests.add('Sara');
  print(visitors);
  print(guests);
}
output
{Ali}
{Sara}

4. add — and the bool It Returns

add puts a value in the set. Unlike a list's add, it answers a question: it returns true if the value was new and false if it was already there.

dart
void main() {
  var visitors = <String>{};
  print(visitors.add('Ali'));
  print(visitors.add('Sara'));
  print(visitors.add('Ali'));
  print(visitors);
}
output
true
true
false
{Ali, Sara}

The second 'Ali' was ignored — no error, just false.


5. addAll — Many Values at Once

addAll adds every value from a list (or another set). Repeats are dropped as they arrive:

dart
void main() {
  var colors = {'red'};
  colors.addAll(['blue', 'red', 'green', 'blue']);
  print(colors);
}
output
{red, blue, green}

6. Order: Insertion Order, but No Indexes

In maths, a set has no order. Dart's everyday set — called a LinkedHashSet — remembers the order in which values were first added, so printing and looping are predictable:

dart
void main() {
  var numbers = {30, 10, 20};
  numbers.add(5);
  numbers.remove(10);
  numbers.add(10);
  print(numbers);
}
output
{30, 20, 5, 10}

Nothing is sorted. 10 went to the end because it was added again after being removed. But a set has no indexes:

dart
void main() {
  var names = {'Ali', 'Sara'};
  print(names[0]); // ✗ sets have no []
}
output
Error: The operator '[]' isn't defined for the type 'Set<String>'.

first and last still work. If you need positions, a list is the right tool.


7. remove — Also Returns a bool

remove deletes a value and returns true if it was there, false if not. A set holds each value once, so there is never a "second copy" left behind.

dart
void main() {
  var tasks = {'cook', 'study', 'sleep'};
  print(tasks.remove('study'));
  print(tasks.remove('swim'));
  print(tasks);
}
output
true
false
{cook, sleep}

8. contains, length and isEmpty

contains asks "is this value in the set?". It is a set's main job, and sets answer it very fast, even with thousands of values.

dart
void main() {
  var members = {'Ali', 'Sara', 'Zayan'};
  print(members.contains('Sara'));
  print(members.contains('Hina'));
  print(members.length);
  print(members.isEmpty);
}
output
true
false
3
false

9. Looping Over a Set

A for-in loop visits every element once, in insertion order:

dart
void main() {
  var subjects = {'Math', 'Science', 'English'};
  for (final subject in subjects) {
    print('Subject: $subject');
  }
}
output
Subject: Math
Subject: Science
Subject: English

As with lists, never add or remove inside a for-in over the same set — Dart stops with a ConcurrentModificationError.


10. List → Set → List: Removing Duplicates

toSet() turns a list into a set, which drops the repeats. toList() turns the set back into a list. Each value keeps the position of its first appearance.

dart
void main() {
  var visitors = ['Ali', 'Sara', 'Ali', 'Zayan', 'Sara'];
  var unique = visitors.toSet();
  var cleanList = unique.toList();
  print(unique);
  print(cleanList);
  print('${visitors.length} visits, ${unique.length} people');
}
output
{Ali, Sara, Zayan}
[Ali, Sara, Zayan]
5 visits, 3 people

Notice the brackets: unique prints with braces, cleanList with square brackets. You can write it in one line too: visitors.toSet().toList().


11. A Real-World Example

dart
void main() {
  var scans = ['Ali', 'Sara', 'Ali', 'Zayan', 'Sara', 'Hina'];
  final present = <String>{};

  for (final name in scans) {
    if (!present.add(name)) {
      print('$name already checked in');
    }
  }

  print('Present: $present');
  print('Count: ${present.length}');
  print(present.contains('Bilal') ? 'Bilal came' : 'Bilal is absent');
}
output
Ali already checked in
Sara already checked in
Present: {Ali, Sara, Zayan, Hina}
Count: 4
Bilal is absent

A door scanner records every swipe. add both stores the name and tells us whether it was new; ! (Lecture 019) flips it, so we print a message only for repeats. The loop walks scans, not present, so changing present inside it is safe.


Code Examples

Example 1 — A Set Literal

dart
void main() {
  var fruits = {'apple', 'mango', 'banana'};
  print(fruits);
  print(fruits.length);
}
output
{apple, mango, banana}
3

Example 2 — Building an Empty Set

dart
void main() {
  Set<int> rolls = {};
  rolls.add(4);
  rolls.add(6);
  rolls.add(4);
  print(rolls);
}
output
{4, 6}

Example 3 — Reading the add Result

dart
void main() {
  var usernames = {'ali99', 'sara_k'};
  var added = usernames.add('sara_k');
  print(added ? 'Welcome!' : 'Username taken');
}
output
Username taken

Example 4 — remove and contains

dart
void main() {
  var lights = {'kitchen', 'hall', 'garden'};
  lights.remove('hall');
  print(lights.contains('hall'));
  print(lights);
}
output
false
{kitchen, garden}

Example 5 — First and Last

dart
void main() {
  var queue = {'Ali', 'Sara', 'Zayan'};
  print(queue.first);
  print(queue.last);
}
output
Ali
Zayan

Example 6 — Unique Letters

dart
void main() {
  var letters = 'banana'.split('').toSet();
  print(letters);
  print('Unique letters: ${letters.length}');
}
output
{b, a, n}
Unique letters: 3

split('') (Lecture 027) gives a list of characters; toSet() keeps one of each.

Example 7 — Student Marks: Distinct Scores

dart
void main() {
  var marks = [85, 92, 85, 78, 92, 85];
  var distinct = marks.toSet();
  print('All marks: $marks');
  print('Distinct marks: $distinct');
  print('Different scores: ${distinct.length}');
}
output
All marks: [85, 92, 85, 78, 92, 85]
Distinct marks: {85, 92, 78}
Different scores: 3

How it works

  1. toSet() keeps the first 85, 92 and 78 and drops the repeats.
  2. The original list is unchanged; toSet() creates a new set.

Example 8 — Shopping Cart Without Repeats

dart
void main() {
  final cart = <String>{};
  var clicks = ['Milk', 'Bread', 'Milk', 'Eggs', 'Bread'];
  for (final item in clicks) {
    cart.add(item);
  }
  print('Cart: $cart');
  print('Items: ${cart.length}');
}
output
Cart: {Milk, Bread, Eggs}
Items: 3

How it works

  1. The customer tapped "add" five times, but only three different products.
  2. The set ignores the repeated taps, so no item appears twice.
  3. final is fine: the set changes, the variable does not.

Example 9 — Bank: Accounts That Made a Payment

dart
void main() {
  var payments = ['ACC-1', 'ACC-3', 'ACC-1', 'ACC-2', 'ACC-3'];
  var payers = payments.toSet();
  for (final account in payers) {
    print('$account paid');
  }
  print(payers.contains('ACC-4') ? 'ACC-4 paid' : 'ACC-4 has not paid');
}
output
ACC-1 paid
ACC-3 paid
ACC-2 paid
ACC-4 has not paid

How it works

  1. toSet() turns five payments into three accounts.
  2. The loop visits each account once, in the order of its first payment.
  3. contains answers the "has this account paid?" question directly.

Example 10 — Temperature: Days Above 30

dart
void main() {
  var readings = [28.5, 31.0, 33.5, 29.0, 31.0, 33.5];
  var hotReadings = <double>{};
  for (final t in readings) {
    if (t > 30) {
      hotReadings.add(t);
    }
  }
  print('Hot readings: $hotReadings');
  print(hotReadings.toList());
}
output
Hot readings: {31.0, 33.5}
[31.0, 33.5]

How it works

  1. Only values above 30 are added, and each appears once.
  2. toList() turns the result back into a list, ready for anything that needs indexes.

Common Beginner Mistakes

1. Using {} for an empty set

dart
void main() {
  var tags = {};
  // tags.add('dart'); // ✗ tags is a Map
}
output
Error: The method 'add' isn't defined for the type 'Map<dynamic, dynamic>'.

Write <String>{} or Set<String> tags = {};.

2. Reading a set by index

dart
void main() {
  var names = {'Ali', 'Sara'};
  // print(names[0]); // ✗
}
output
Error: The operator '[]' isn't defined for the type 'Set<String>'.

Use first, a loop, or convert with toList() if you really need positions.

3. Writing a duplicate in a literal

dart
void main() {
  // var numbers = {1, 2, 2, 3}; // ⚠ runs, prints {1, 2, 3}
  // const fixed = {1, 1}; // ✗
}

The first line runs, but dart analyze warns: Two elements in a set literal shouldn't be equal. With const it is an error: The element '1' conflicts with another existing element in the set. A duplicate in your own literal is almost always a typo.

4. Expecting add to fail loudly

Adding an existing value is not an error. If you care, check the bool: if (!names.add(name)) { … }.

5. Expecting a set to sort its values

{30, 10, 20} prints as {30, 10, 20}. A set keeps insertion order, not number order. Sorting belongs to lists (Lecture 045).

6. Changing a set while looping over it

dart
void main() {
  var tags = {'dart', 'code'};
  for (final tag in tags) {
    // if (tag == 'dart') tags.remove(tag); // ✗
  }
}
output
Unhandled exception:
Concurrent modification during iteration: _Set len:1.

Loop over a different collection, or change the set after the loop.

7. Braces after =>

As in Lecture 034, int square(int n) => {n * n}; returns a Set<int>, not an int. Use the arrow or braces, never both.


Best Practices

  • Choose a set when values must be unique and you mostly ask "is it there?".
  • Choose a list when order by position, indexes, or repeats matter.
  • Always give an empty set a type: <String>{} or Set<String> x = {};.
  • Use the bool from add instead of calling contains and then add.
  • Use toSet().toList() to remove duplicates from a list in one line.
  • Declare a set you will add to with final.

Mini Challenge

A teacher writes down the subjects students ask about: ['Math', 'Art', 'Math', 'Science', 'Art', 'Math']. Print each subject once, then how many different subjects there were.

output
Math
Art
Science
Subjects: 3

Try it yourself before opening the solution.

Show solution
dart
void main() {
  var requests = ['Math', 'Art', 'Math', 'Science', 'Art', 'Math'];
  var subjects = requests.toSet();
  for (final subject in subjects) {
    print(subject);
  }
  print('Subjects: ${subjects.length}');
}
output
Math
Art
Science
Subjects: 3

Practice Questions

Work through these in order — they run from beginner to application to challenge.

Beginner

  1. Create a set of the numbers 1, 2, 3 and print it and its length.
  2. Create an empty Set<String>, add 'Ali' and 'Sara', and print it.
  3. Start with {'red', 'green'}. Print the result of adding 'red', then the result of adding 'blue', then the set.

Application

  1. Start with {'cook', 'clean', 'study'}. Remove 'clean', then print whether the set contains 'clean', and the set.
  2. Turn the list [4, 8, 4, 15, 8, 4] into a set and print it.
  3. Remove the duplicates from ['a', 'b', 'a', 'c', 'b'] and print the result as a list.
  4. Loop over {'Ali', 'Sara', 'Zayan'} and print Hello, <name>! for each name.
  5. Explain why var s = {}; s.add(1); does not compile, then fix the first statement so it prints {1}.

Challenge

  1. Given the votes ['A', 'B', 'A', 'C', 'B', 'A'], use a set and the bool from add to print Repeat vote: <vote> for every vote already seen, then print the set of options.
  2. Given the words in 'the cat and the dog and the bird', print how many words there are in total and how many different words, in the form Words: 8, Different: 5.

Practice Answers

Question 1 — Solution

dart
void main() {
  var numbers = {1, 2, 3};
  print(numbers);
  print(numbers.length);
}
output
{1, 2, 3}
3

Question 2 — Solution

dart
void main() {
  var names = <String>{};
  names.add('Ali');
  names.add('Sara');
  print(names);
}
output
{Ali, Sara}

Question 3 — Solution

dart
void main() {
  var colors = {'red', 'green'};
  print(colors.add('red'));
  print(colors.add('blue'));
  print(colors);
}
output
false
true
{red, green, blue}

Question 4 — Solution

dart
void main() {
  var chores = {'cook', 'clean', 'study'};
  chores.remove('clean');
  print(chores.contains('clean'));
  print(chores);
}
output
false
{cook, study}

Question 5 — Solution

dart
void main() {
  var numbers = [4, 8, 4, 15, 8, 4];
  print(numbers.toSet());
}
output
{4, 8, 15}

Question 6 — Solution

dart
void main() {
  var letters = ['a', 'b', 'a', 'c', 'b'];
  var unique = letters.toSet().toList();
  print(unique);
}
output
[a, b, c]

Question 7 — Solution

dart
void main() {
  var names = {'Ali', 'Sara', 'Zayan'};
  for (final name in names) {
    print('Hello, $name!');
  }
}
output
Hello, Ali!
Hello, Sara!
Hello, Zayan!

Question 8 — Solution

Empty braces make a Map<dynamic, dynamic>, and a Map has no add method. Give the type:

dart
void main() {
  var s = <int>{};
  s.add(1);
  print(s);
}
output
{1}

Question 9 — Solution

dart
void main() {
  var votes = ['A', 'B', 'A', 'C', 'B', 'A'];
  final options = <String>{};
  for (final vote in votes) {
    if (!options.add(vote)) {
      print('Repeat vote: $vote');
    }
  }
  print(options);
}
output
Repeat vote: A
Repeat vote: B
Repeat vote: A
{A, B, C}

Question 10 — Solution

dart
void main() {
  var words = 'the cat and the dog and the bird'.split(' ');
  var different = words.toSet();
  print('Words: ${words.length}, Different: ${different.length}');
}
output
Words: 8, Different: 5

split(' ') cuts the sentence at each space. The set keeps the, cat, and, dog and bird once each.


Quick Revision

  1. What makes a set different from a list?
  2. Which brackets create a set literal?
  3. What type does var x = {}; have?
  4. Name two ways to write an empty set of strings.
  5. What does add return when the value is already in the set?
  6. Does a set keep any order? Can you read set[0]?
  7. How do you remove duplicates from a list and get a list back?

Key Takeaways

  • A set holds each value at most once; adding a duplicate is silently ignored.
  • Set literals use curly braces: {'Ali', 'Sara'}; Set<int> gives the element type.
  • {} alone is a Map — write <String>{} or Set<String> x = {}; for an empty set.
  • add and remove return a bool: true if the set changed, false if not.
  • contains, length, isEmpty, first and last work as on lists.
  • Dart's default set (LinkedHashSet) keeps insertion order, but has no indexes.
  • for-in visits each element once; don't change the set inside that loop.
  • list.toSet() removes duplicates; set.toList() turns it back into a list.

What's Next?

Lecture 48 — Set Operations. One set answers "is this value in here?". Often we have two sets — students in the chess club and in the art club — and want to know who is in both, who is in either, and who is in only one. Next we will combine sets with union, intersection, and difference.


Video lecture

Subscribe
Placeholder video — the real recording isn't linked yet.