On this page23 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. What Is a Set?
- 2. Giving a Set a Type
- 3. {} on Its Own Is a Map, Not a Set
- 4. add — and the bool It Returns
- 5. addAll — Many Values at Once
- 6. Order: Insertion Order, but No Indexes
- 7. remove — Also Returns a bool
- 8. contains, length and isEmpty
- 9. Looping Over a Set
- 10. List → Set → List: Removing Duplicates
- 11. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 47 — Sets
| Category | 8 — Sets & Maps |
| Lecture | 047 of 140 |
| Estimated video length | 10 min |
| Target | Dart 3.12.2 |
| Level | Beginner |
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:
finalvariables (Lecture 006) andfor-inloops (Lecture 027)- the conditional expression
? :(Lecture 023) - creating lists,
List<int>,length, andisEmpty(Lecture 039) add,removeand theConcurrentModificationError(Lecture 041)contains(Lecture 042)
Connection With Previous Lectures
Lists keep everything you give them, including repeats:
void main() {
var visitors = ['Ali', 'Sara', 'Ali', 'Zayan', 'Sara'];
print(visitors.length);
}5Five 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 andSet<T>types - Create an empty set correctly, knowing that
{}alone is a Map - Use
addand read thetrue/falseit returns - Use
remove,contains,length, andisEmpty - Loop over a set with
for-in - Remove duplicates from a list with
toSet()and turn the result back withtoList() - 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:
void main() {
var names = {'Ali', 'Sara', 'Zayan'};
print(names);
print(names.length);
}{Ali, Sara, Zayan}
3Dart 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".
void main() {
Set<int> marks = {85, 92, 78};
Set<String> cities = {'Karachi', 'Lahore'};
print(marks);
print(cities);
}{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:
void main() {
var visitors = {};
print(visitors.runtimeType);
}_Map<dynamic, dynamic>runtimeType (Lecture 010) reveals the truth — it is a Map, and a Map has no add:
void main() {
var visitors = {};
visitors.add('Ali'); // ✗ visitors is a Map
}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:
void main() {
Set<String> visitors = {};
var guests = <String>{};
visitors.add('Ali');
guests.add('Sara');
print(visitors);
print(guests);
}{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.
void main() {
var visitors = <String>{};
print(visitors.add('Ali'));
print(visitors.add('Sara'));
print(visitors.add('Ali'));
print(visitors);
}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:
void main() {
var colors = {'red'};
colors.addAll(['blue', 'red', 'green', 'blue']);
print(colors);
}{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:
void main() {
var numbers = {30, 10, 20};
numbers.add(5);
numbers.remove(10);
numbers.add(10);
print(numbers);
}{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:
void main() {
var names = {'Ali', 'Sara'};
print(names[0]); // ✗ sets have no []
}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.
void main() {
var tasks = {'cook', 'study', 'sleep'};
print(tasks.remove('study'));
print(tasks.remove('swim'));
print(tasks);
}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.
void main() {
var members = {'Ali', 'Sara', 'Zayan'};
print(members.contains('Sara'));
print(members.contains('Hina'));
print(members.length);
print(members.isEmpty);
}true
false
3
false9. Looping Over a Set
A for-in loop visits every element once, in insertion order:
void main() {
var subjects = {'Math', 'Science', 'English'};
for (final subject in subjects) {
print('Subject: $subject');
}
}Subject: Math
Subject: Science
Subject: EnglishAs 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.
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');
}{Ali, Sara, Zayan}
[Ali, Sara, Zayan]
5 visits, 3 peopleNotice 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
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');
}Ali already checked in
Sara already checked in
Present: {Ali, Sara, Zayan, Hina}
Count: 4
Bilal is absentA 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
void main() {
var fruits = {'apple', 'mango', 'banana'};
print(fruits);
print(fruits.length);
}{apple, mango, banana}
3Example 2 — Building an Empty Set
void main() {
Set<int> rolls = {};
rolls.add(4);
rolls.add(6);
rolls.add(4);
print(rolls);
}{4, 6}Example 3 — Reading the add Result
void main() {
var usernames = {'ali99', 'sara_k'};
var added = usernames.add('sara_k');
print(added ? 'Welcome!' : 'Username taken');
}Username takenExample 4 — remove and contains
void main() {
var lights = {'kitchen', 'hall', 'garden'};
lights.remove('hall');
print(lights.contains('hall'));
print(lights);
}false
{kitchen, garden}Example 5 — First and Last
void main() {
var queue = {'Ali', 'Sara', 'Zayan'};
print(queue.first);
print(queue.last);
}Ali
ZayanExample 6 — Unique Letters
void main() {
var letters = 'banana'.split('').toSet();
print(letters);
print('Unique letters: ${letters.length}');
}{b, a, n}
Unique letters: 3split('') (Lecture 027) gives a list of characters; toSet() keeps one of each.
Example 7 — Student Marks: Distinct Scores
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}');
}All marks: [85, 92, 85, 78, 92, 85]
Distinct marks: {85, 92, 78}
Different scores: 3How it works
toSet()keeps the first85,92and78and drops the repeats.- The original list is unchanged;
toSet()creates a new set.
Example 8 — Shopping Cart Without Repeats
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}');
}Cart: {Milk, Bread, Eggs}
Items: 3How it works
- The customer tapped "add" five times, but only three different products.
- The set ignores the repeated taps, so no item appears twice.
finalis fine: the set changes, the variable does not.
Example 9 — Bank: Accounts That Made a Payment
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');
}ACC-1 paid
ACC-3 paid
ACC-2 paid
ACC-4 has not paidHow it works
toSet()turns five payments into three accounts.- The loop visits each account once, in the order of its first payment.
containsanswers the "has this account paid?" question directly.
Example 10 — Temperature: Days Above 30
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());
}Hot readings: {31.0, 33.5}
[31.0, 33.5]How it works
- Only values above
30are added, and each appears once. toList()turns the result back into a list, ready for anything that needs indexes.
Common Beginner Mistakes
1. Using {} for an empty set
void main() {
var tags = {};
// tags.add('dart'); // ✗ tags is a Map
}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
void main() {
var names = {'Ali', 'Sara'};
// print(names[0]); // ✗
}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
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
void main() {
var tags = {'dart', 'code'};
for (final tag in tags) {
// if (tag == 'dart') tags.remove(tag); // ✗
}
}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>{}orSet<String> x = {};. - Use the
boolfromaddinstead of callingcontainsand thenadd. - 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.
Math
Art
Science
Subjects: 3Try it yourself before opening the solution.
Show solution
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}');
}Math
Art
Science
Subjects: 3Practice Questions
Work through these in order — they run from beginner to application to challenge.
Beginner
- Create a set of the numbers
1,2,3and print it and its length. - Create an empty
Set<String>, add'Ali'and'Sara', and print it. - Start with
{'red', 'green'}. Print the result of adding'red', then the result of adding'blue', then the set.
Application
- Start with
{'cook', 'clean', 'study'}. Remove'clean', then print whether the set contains'clean', and the set. - Turn the list
[4, 8, 4, 15, 8, 4]into a set and print it. - Remove the duplicates from
['a', 'b', 'a', 'c', 'b']and print the result as a list. - Loop over
{'Ali', 'Sara', 'Zayan'}and printHello, <name>!for each name. - Explain why
var s = {}; s.add(1);does not compile, then fix the first statement so it prints{1}.
Challenge
- Given the votes
['A', 'B', 'A', 'C', 'B', 'A'], use a set and theboolfromaddto printRepeat vote: <vote>for every vote already seen, then print the set of options. - 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 formWords: 8, Different: 5.
Practice Answers
Question 1 — Solution
void main() {
var numbers = {1, 2, 3};
print(numbers);
print(numbers.length);
}{1, 2, 3}
3Question 2 — Solution
void main() {
var names = <String>{};
names.add('Ali');
names.add('Sara');
print(names);
}{Ali, Sara}Question 3 — Solution
void main() {
var colors = {'red', 'green'};
print(colors.add('red'));
print(colors.add('blue'));
print(colors);
}false
true
{red, green, blue}Question 4 — Solution
void main() {
var chores = {'cook', 'clean', 'study'};
chores.remove('clean');
print(chores.contains('clean'));
print(chores);
}false
{cook, study}Question 5 — Solution
void main() {
var numbers = [4, 8, 4, 15, 8, 4];
print(numbers.toSet());
}{4, 8, 15}Question 6 — Solution
void main() {
var letters = ['a', 'b', 'a', 'c', 'b'];
var unique = letters.toSet().toList();
print(unique);
}[a, b, c]Question 7 — Solution
void main() {
var names = {'Ali', 'Sara', 'Zayan'};
for (final name in names) {
print('Hello, $name!');
}
}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:
void main() {
var s = <int>{};
s.add(1);
print(s);
}{1}Question 9 — Solution
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);
}Repeat vote: A
Repeat vote: B
Repeat vote: A
{A, B, C}Question 10 — Solution
void main() {
var words = 'the cat and the dog and the bird'.split(' ');
var different = words.toSet();
print('Words: ${words.length}, Different: ${different.length}');
}Words: 8, Different: 5split(' ') cuts the sentence at each space. The set keeps the, cat, and, dog and
bird once each.
Quick Revision
- What makes a set different from a list?
- Which brackets create a set literal?
- What type does
var x = {};have? - Name two ways to write an empty set of strings.
- What does
addreturn when the value is already in the set? - Does a set keep any order? Can you read
set[0]? - 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>{}orSet<String> x = {};for an empty set.addandremovereturn abool:trueif the set changed,falseif not.contains,length,isEmpty,firstandlastwork as on lists.- Dart's default set (
LinkedHashSet) keeps insertion order, but has no indexes. for-invisits 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.