ITC 120 › Final › Sets and maps
Sets and maps · Lesson 1 of 2
Sets in Java
This lesson teaches:Abstract data type (ADT)A collection with one simple promise: no duplicates.
By the end, you can:
- explain what a set is (an ADT with unique, unordered values) and tell when a problem needs a set instead of a list;
- write A ∪ B, A ∩ B, A − B, B − A, and A △ B for two given sets, draw them on a Venn diagram, and (extra) tell whether one set is a subset of another;
- predict what
add,contains,remove, andsizereturn on a JavaHashSet; - write each set operation in Java with
addAll,retainAll, orremoveAllon a copy, (extra) check a subset withcontainsAll, and find the bug when a copy is missing or the wrong set is used; - choose between
HashSet,LinkedHashSet, andTreeSetby the order you need.
You need: scratch paper. You may also remember sets from math class; the ideas are the same.
Part 1 · The idea
What a set is
Set
A set is an abstract data type (ADT, explained below) that stores a collection of values with no duplicates and no fixed order. The main question a set answers is: "Is this value in the collection or not?"
What is an abstract data type (ADT)?
Every data structure can be described by answering two questions:
- What can I do with it? Its operations, and what each one gives back. For a set: add a value, remove a value, ask "Is this value in it?", and count the values.
- How is it stored inside the computer? For a set, it could be an array, a tree, or a hash table. Any of these can work.
An abstract data type (ADT) answers only the first question. "Abstract" means "the idea only, without the details". So the ADT says what you can do, not how it is done. The second question is answered by the code that builds it, called the implementation.
This table matches the store to a set:
| In the store | In a set |
|---|---|
| You ask: "Do you have Coke?" | contains("Coke"): the answer is yes or no (true or false) |
| New stock arrives | add("Coke") |
| The last one is sold | remove("Coke") |
| How the shelves or bins are arranged (you can't see it) | how the set is built inside: the implementation |
Why split it this way? You can use a set without knowing how it is built, just as you can buy at any sari-sari store without seeing its shelves. And the way it is built can be changed later (to make it faster) without changing the code that uses it.
You already met this idea in the Stacks lesson: what made a stack a stack was the rule "push, pop, peek", not whether it was built with an array or a linked list. Now the idea has a name. A set is described the same way: "add, remove, contains".
Good to know: this course calls stacks and queues data structures and sets and maps abstract data types. Many books call stacks and queues ADTs too, because they can also be described only by what you can do with them. Both views are correct.
The two properties
Every set has these two properties:
- Uniqueness. Each value appears at most once (like the second Ana in the list vs. set picture ). Adding a value that is already there does nothing.
- Unordered. Items have no position (no place in line). In a list or an array, every item has an index:
[0]is the first item,[1]is the second, and so on. A set has no index, so it has no "first" item. You can only ask "Is this value in the set?" That is why {1, 2, 3} and {3, 1, 2} are the same set.
Think of the attendance list
When students tap their ID at the door, some tap twice. But the attendance should list each student once, and it does not matter who came first. That is a set. Compare with the queue at the canteen: there, order matters and the same person can line up again. That is a list or a queue, not a set.
Where you see sets in IT
- Counting unique visitors to a website (the same person visiting 5 times counts once).
- Tags on a post, or the list of permissions a user has.
- Comparing two class lists: who is enrolled in both subjects? (intersection)
Review: subsets (extra)
Extra topic. Subsets go a little beyond this course's required set topics (properties, union, intersection, difference, symmetric difference). Study it if you have time; your teacher will tell you if a quiz or exam uses it.
You may remember subsets from math class. Here is a quick review, because Java can check them too (Part 3).
Subset
A is a subset of B, written A ⊆ B, when every value in A is also in B.
Here are the words and symbols that go with subsets, using the sets in the picture:
| Term | Symbol | Meaning | Example |
|---|---|---|---|
| Subset | A ⊆ B | every value of A is in B | {Ana, Ben} ⊆ B |
| Proper subset | A ⊂ B | A ⊆ B, and B has at least one value that A does not | {Ana, Ben} ⊂ B (B also has Carla and Dan) |
| Not a subset | C ⊄ B | at least one value of C is not in B | {Ana, Eve} ⊄ B (Eve) |
| Equal sets | A = B | A ⊆ B and B ⊆ A: exactly the same values | {Ana, Ben} = {Ben, Ana} |
Two facts are easy to forget:
- The empty set { } (the set with nothing in it) is a subset of every set. It has no value that could be missing from B.
- Every set is a subset of itself (B ⊆ B), but not a proper subset of itself.
Exam trap: one value vs. a set
Ana ∈ B means "the value Ana is in B" (∈ = "is an element of"). {Ana} ⊆ B means "the set holding only Ana is a subset of B". Use ∈ for one value and ⊆ for a set. Writing "Ana ⊆ B" is wrong.
Extra: ⊂ in other books
Extra topic. Open this if a book you read writes ⊂ differently.
Some books write ⊂ for any subset (what we write ⊆). If a question uses ⊂, check how that book or teacher defines it. Rosen (reference 3) uses ⊆ and ⊂ the same way as this lesson.
Part 2 · Combining sets
Set operations
Set operations take two sets and produce a new set. There are four types you need to know. In the examples, A = {1, 2, 3, 4, 5} and B = {4, 5, 6, 7}.
| Operation | Symbol | Meaning | Example |
|---|---|---|---|
| Union | A ∪ B | in A or B (or both) | {1, 2, 3, 4, 5, 6, 7} |
| Intersection | A ∩ B | in A and B | {4, 5} |
| Difference | A − B | in A but not in B | {1, 2, 3} |
| Difference | B − A | in B but not in A | {6, 7} |
| Symmetric difference | A △ B | in A or B, but not both | {1, 2, 3, 6, 7} |
The lab below draws each operation on a Venn diagram: one circle per set. Values in both sets go in the overlap in the middle; values in only one set go in that circle's outer part. The shaded part is the answer.
Set operations lab
Pick an operation to shade its part of the picture. You can also change A and B (whole numbers, separated by commas).
Exam traps
A − B is not the same as B − A. Order matters for difference: A − B is the part of A outside B, and B − A is the part of B outside A.
In a union, shared values appear once: {1, 2} ∪ {2, 3} = {1, 2, 3}, not {1, 2, 2, 3}.
When the result has nothing in it, write the empty set: { } (or ∅). Here A and B have the same values, so their circles sit on top of each other and A − B leaves nothing. Try making A and B equal in the lab.
A △ B = (A ∪ B) − (A ∩ B) = (A − B) ∪ (B − A). All three give the same answer: the two outer parts, without the middle.
Extra: other symbols in other books
Extra topic. Open this if a book you read uses other symbols.
Some books write the difference A − B as A \ B, and the symmetric difference A △ B as A ⊕ B (Rosen, reference 3) or A Δ B. They mean the same operations.
Part 3 · In code
Sets in Java
Remember the sari-sari store : what you can ask is one thing, and how the stock is arranged inside is another. Java splits a set into the same two parts:
- What a set can do:
Setis an interface . It lists the methods every set must have (add,contains,remove,size, and more), but has no code inside. This is the ADT. - How it is built:
HashSet,LinkedHashSet, andTreeSetare classes . Each one writes the real code for those methods in its own way. We say each class implementsSet.
Here are the three main classes:
| Class | Built with | Order when you loop through it |
|---|---|---|
HashSet | a hash table, through a HashMap inside (next lesson) | no guaranteed order |
LinkedHashSet | a hash table + a linked list | the order you added them |
TreeSet | a red-black tree, through a TreeMap inside | sorted |
Wait: Part 1 said a set has no order. The set ADT promises no order, so you can never ask for "item [2]". LinkedHashSet and TreeSet add an order as an extra, only for looping through the values. They still have no index, and they still keep each value once.
You will see both parts in one line of code: Set<String> present = new HashSet<>(); reads as "present is a Set of Strings, built as a HashSet." The left side (Set) says what you may do with it. The right side (new HashSet<>()) picks how it is built. To get sorted order instead, you would change only the right side, to new TreeSet<>().
HashSet is the usual choice. Its basic methods are add, contains, remove, and size:
import java.util.HashSet;
import java.util.Set;
public class Attendance {
public static void main(String[] args) {
Set<String> present = new HashSet<>();
present.add("Ana");
present.add("Ben");
present.add("Carla");
boolean added = present.add("Ana"); // already there
System.out.println(added); // false
System.out.println(present.size()); // 3
System.out.println(present.contains("Ben")); // true
System.out.println(present.contains("Dan")); // false
present.remove("Ben");
System.out.println(present.size()); // 2
for (String name : present) { // order not guaranteed
System.out.println(name);
}
}
} ▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class Attendance to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.
Set operations in Java
Java does not have methods named "union" or "intersection". Instead, three methods do the work. Each one changes the set it is called on:
| Method | What it does to x | Operation |
|---|---|---|
x.addAll(y) | adds every value of y into x | union |
x.retainAll(y) | keeps only the values that are also in y | intersection |
x.removeAll(y) | takes out every value that is in y | difference |
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class SetOperations {
public static void main(String[] args) {
Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(4, 5, 6, 7));
Set<Integer> union = new HashSet<>(a); // copy of A
union.addAll(b); // add all of B
System.out.println("A u B = " + union); // [1, 2, 3, 4, 5, 6, 7]
Set<Integer> inter = new HashSet<>(a);
inter.retainAll(b); // keep only what B has
System.out.println("A n B = " + inter); // [4, 5]
Set<Integer> aMinusB = new HashSet<>(a);
aMinusB.removeAll(b); // take out B's values
System.out.println("A - B = " + aMinusB); // [1, 2, 3]
Set<Integer> bMinusA = new HashSet<>(b);
bMinusA.removeAll(a);
System.out.println("B - A = " + bMinusA); // [6, 7]
Set<Integer> sym = new HashSet<>(union); // A u B ...
sym.removeAll(inter); // ... minus A n B
System.out.println("A sym B = " + sym); // [1, 2, 3, 6, 7]
System.out.println("A is still " + a); // [1, 2, 3, 4, 5]
}
} ▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class SetOperations to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.
The code prints u, n, and sym instead of ∪, ∩, and △, because some consoles cannot show those symbols. Small whole numbers like these usually come out in increasing order from a HashSet, but that is not guaranteed (the names in the attendance example did not). The values are what matter, not their order.
The #1 bug: forgetting to copy
Because addAll, retainAll, and removeAll change the set itself, always start from a copy: new HashSet<>(a). If you write a.addAll(b) directly, A is now the union, and every later operation that uses A gives the wrong answer.
Spot the bug
This code should print A − B and B − A. The B − A part was copied from the A − B part, and two lines were not fully updated. Which lines, and what does the code print?
1Set<Integer> a = new HashSet<>(Arrays.asList(10, 20, 30));
2Set<Integer> b = new HashSet<>(Arrays.asList(20, 40));
3
4Set<Integer> aMinusB = new HashSet<>(a);
5aMinusB.removeAll(b);
6System.out.println("A - B: " + aMinusB);
7
8Set<Integer> bMinusA = new HashSet<>(b);
9aMinusB.removeAll(a);
10System.out.println("B - A: " + aMinusB); Show the answer
Lines 9 and 10 still use aMinusB. Line 9 should be bMinusA.removeAll(a);, and line 10 should print bMinusA.
As written, it prints A - B: [10, 30], then removes A's values from aMinusB (which empties it) and prints B - A: []. The correct B − A is {40}.
This kind of copy-paste mistake is common. When you copy a block of code, check every variable name in it.
Subsets in Java (extra)
Extra topic, like the subsets review in Part 1.
Java has no method named "subset". You check A ⊆ B with containsAll. This table shows each subset question in Java:
| By hand | In Java | Read it as |
|---|---|---|
| A ⊆ B | b.containsAll(a) | "Does b contain all of a?" |
| A ⊂ B | b.containsAll(a) && !a.equals(b) | "all of a, and not the same set" |
| A = B | a.equals(b) | "exactly the same values?" |
| x ∈ B | b.contains(x) | "is this one value in b?" |
Watch the direction: A ⊆ B is written b.containsAll(a), so the bigger set goes first. And unlike addAll, retainAll, and removeAll, containsAll changes nothing. It only answers true or false, so no copy is needed.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
public class Subsets {
public static void main(String[] args) {
Set<String> b = new HashSet<>(Arrays.asList("Ana", "Ben", "Carla", "Dan"));
Set<String> a = new HashSet<>(Arrays.asList("Ana", "Ben"));
Set<String> c = new HashSet<>(Arrays.asList("Ana", "Eve"));
Set<String> empty = new HashSet<>();
System.out.println(b.containsAll(a)); // true: A is a subset of B
System.out.println(b.containsAll(c)); // false: Eve is not in B
System.out.println(b.containsAll(empty)); // true: { } is a subset of every set
System.out.println(a.containsAll(a)); // true: every set is a subset of itself
boolean proper = b.containsAll(a) && !a.equals(b);
System.out.println(proper); // true: A is a proper subset of B
Set<String> d = new TreeSet<>(Arrays.asList("Dan", "Carla", "Ben", "Ana"));
System.out.println(b.equals(d)); // true: same values (order and class don't matter)
System.out.println(b.contains("Ana")); // true: one value, so contains
System.out.println(a.size() + " " + b.size()); // 2 4: containsAll changed nothing
}
} ▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class Subsets to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.
equals ignores order, and even the class: a HashSet and a TreeSet with the same values are equal.
Part 4 · Your turn
Practice
For each pair, write A ∪ B, A ∩ B, A − B, B − A, and A △ B. Drawing a quick Venn diagram first makes it easy: put shared values in the middle. After the four problems, a short coding task turns one of these operations into Java.
Problem 1
A = { 2, 4, 6, 8, 10 }
B = { 3, 6, 9, 12 }
Show the answer
| A ∪ B | { 2, 3, 4, 6, 8, 9, 10, 12 } |
|---|---|
| A ∩ B | { 6 } |
| A − B | { 2, 4, 8, 10 } |
| B − A | { 3, 9, 12 } |
| A △ B | { 2, 3, 4, 8, 9, 10, 12 } |
Problem 2
A = { 15, 25, 35, 45 }
B = { 45, 35, 25, 15 }
Show the answer
| A ∪ B | { 15, 25, 35, 45 } |
|---|---|
| A ∩ B | { 15, 25, 35, 45 } |
| A − B | { } |
| B − A | { } |
| A △ B | { } |
A and B have the same values (the order does not matter in a set), so they are equal sets. Nothing is left over in either difference, and nothing is in one but not both.
Problem 3
A = { 1, 2, 3 }
B = { }
Show the answer
| A ∪ B | { 1, 2, 3 } |
|---|---|
| A ∩ B | { } |
| A − B | { 1, 2, 3 } |
| B − A | { } |
| A △ B | { 1, 2, 3 } |
B is the empty set. Union with an empty set changes nothing, and intersection with it is always empty.
Problem 4: the library tap-in log
Students tap their ID cards when they enter the library, and they tap again each time they come back from a break. Monday morning's log, in tap order:
1021, 1045, 1021, 1102, 1045, 1021, 1230
Tuesday's different visitors were {1045, 1230, 1301}.
- How many different students visited on Monday?
- Which students came on both days?
- Which students came on Monday but not on Tuesday?
Show the answer
- Write the log as a set, keeping each ID once: Monday = {1021, 1045, 1102, 1230}. That is 4 different students, even though there were 7 taps.
- Both days = Monday ∩ Tuesday = {1045, 1230}.
- Monday only = Monday − Tuesday = {1021, 1102}.
In Java, the set removes the repeated taps for you. Adding the whole log to a HashSet keeps each ID once:
1import java.util.Arrays;
2import java.util.HashSet;
3import java.util.Set;
4
5public class Library {
6 public static void main(String[] args) {
7 Set<Integer> monday = new HashSet<>(Arrays.asList(1021, 1045, 1021, 1102, 1045, 1021, 1230));
8 Set<Integer> tuesday = new HashSet<>(Arrays.asList(1045, 1230, 1301));
9 System.out.println(monday.size()); // 4: each ID is kept once
10
11 Set<Integer> both = new HashSet<>(monday);
12 both.retainAll(tuesday); // came both days
13 System.out.println(both); // [1045, 1230]
14
15 Set<Integer> mondayOnly = new HashSet<>(monday);
16 mondayOnly.removeAll(tuesday); // Monday but not Tuesday
17 System.out.println(mondayOnly); // [1021, 1102]
18 }
19} ▶ Try it in the Programiz online compiler: tap Copy, paste it there, change public class Library to public class Main (Programiz saves your code as Main.java, and Java needs the file name and the public class name to match), then press Run.
Your coding task: A △ B without changing A or B
In Part 2 , A △ B was the two outer parts of the Venn diagram: (A − B) ∪ (B − A). Now write it in Java.
Finish symDiff in about 5 lines where it says YOUR CODE. Use removeAll and addAll from Part 3, and watch out for the #1 bug: work on copies, so a and b stay the same. The tests use the pairs from Problems 1 to 3 above, so you can compare with your paper answers. Run it: each printed line must match its expected comment.
1import java.util.Arrays;
2import java.util.HashSet;
3import java.util.Set;
4
5public class Main {
6 // Returns A sym B = (A - B) u (B - A).
7 // It must NOT change a or b.
8 static Set<Integer> symDiff(Set<Integer> a, Set<Integer> b) {
9 // YOUR CODE:
10 // 1. Copy a, then remove all of b from the copy (A - B).
11 // 2. Copy b, then remove all of a from the copy (B - A).
12 // 3. Add all of B - A into A - B, and return it.
13
14 return new HashSet<>();
15 }
16
17 public static void main(String[] args) {
18 // Problem 1 from the paper practice
19 Set<Integer> a = new HashSet<>(Arrays.asList(2, 4, 6, 8, 10));
20 Set<Integer> b = new HashSet<>(Arrays.asList(3, 6, 9, 12));
21 System.out.println(symDiff(a, b)); // expected: [2, 3, 4, 8, 9, 10, 12]
22 System.out.println(symDiff(b, a)); // expected: [2, 3, 4, 8, 9, 10, 12]
23 System.out.println(a); // expected: [2, 4, 6, 8, 10] (unchanged)
24 System.out.println(b); // expected: [3, 6, 9, 12] (unchanged)
25
26 // Problem 2: same values, so nothing is left
27 Set<Integer> c = new HashSet<>(Arrays.asList(15, 25, 35, 45));
28 Set<Integer> d = new HashSet<>(Arrays.asList(45, 35, 25, 15));
29 System.out.println(symDiff(c, d)); // expected: []
30
31 // Problem 3: B is the empty set
32 Set<Integer> e = new HashSet<>(Arrays.asList(1, 2, 3));
33 Set<Integer> empty = new HashSet<>();
34 System.out.println(symDiff(e, empty)); // expected: [1, 2, 3]
35 }
36} ▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.
Show one possible answer
1static Set<Integer> symDiff(Set<Integer> a, Set<Integer> b) {
2 Set<Integer> aMinusB = new HashSet<>(a); // copy of A
3 aMinusB.removeAll(b); // A - B
4 Set<Integer> bMinusA = new HashSet<>(b); // copy of B
5 bMinusA.removeAll(a); // B - A
6 aMinusB.addAll(bMinusA); // (A - B) u (B - A)
7 return aMinusB;
8} Output, one per line: [2, 3, 4, 8, 9, 10, 12] twice (A △ B and B △ A are the same set), then [2, 4, 6, 8, 10] and [3, 6, 9, 12] (A and B did not change), then [] and [1, 2, 3].
Another correct answer follows the Part 3 code: copy A and add all of B (the union), copy A and keep only B's values (the intersection), then remove the intersection from the union.
Here is the most common mistake: skipping the copies.
1a.removeAll(b); // no copy: changes a itself
2b.removeAll(a);
3a.addAll(b);
4return a; The first line takes B's values out of A itself, so A is now [2, 4, 8, 10]. The second line removes that changed A from B, which takes out nothing. The last line adds B back, so the method returns [2, 3, 4, 6, 8, 9, 10, 12]: 6 is back, even though it is in both sets. And since a itself was changed, the next tests are wrong too. Every line of the first test prints that same wrong set, and Problem 2 prints all four values instead of [].
Part 5 · Check yourself
Self-check
Not graded. Tap an answer to see if you got it, and read why.
-
Which two properties describe a set?
A set holds each value at most once (unique), and its items have no position or index (unordered).
-
You call
add(5)on a set that already contains 5. What happens?The set ignores the duplicate.
addreturnsfalseto tell you nothing was added. -
A = {1, 2, 3}, B = {3, 4}. What is A ∩ B?
Intersection keeps only what is in both: 3.
-
A = {1, 2, 3}, B = {3, 4}. What is A △ B (symmetric difference)?
Everything in A or B, except what they share: remove 3 from {1, 2, 3, 4}.
-
If A and B are equal sets, what is A − B?
Every value in A is also in B, so removing B's values from A leaves nothing.
-
Which Java method keeps only the elements that are also in another set?
retainAll= "keep only these" = intersection.addAll= union,removeAll= difference.containsAllchanges nothing: it only checks whether every value of the other set is already in this one (a subset test). -
Why do we write
new HashSet<>(a)before callingunion.addAll(b)?addAll,retainAll, andremoveAllall change the set they are called on. Copy first, or you destroy A and get wrong answers in later operations. -
Which Java set keeps its elements in sorted order?
TreeSetkeeps its elements in a red-black tree (through aTreeMapinside), so they come out sorted.HashSethas no guaranteed order;LinkedHashSetkeeps the order you added them. -
(Extra) A = {1, 2} and B = {1, 2, 3}. Which is true?
Every value of A (1 and 2) is in B, and B also has 3, which A does not. So A ⊆ B and A ≠ B: a proper subset. B ⊆ A is false (3 is missing from A), and { } is a subset of every set.
-
(Extra) Which Java line checks whether A ⊆ B?
A ⊆ B means "B contains all of A", so you ask B:
b.containsAll(a).a.containsAll(b)checks the other direction (B ⊆ A),retainAllchangesa, andequalschecks A = B.
Score: 0 / 10
Key takeaways
- A set stores unique values with no order. Duplicates are ignored.
- Union = or. Intersection = and. A − B = in A but not in B (so A − B and B − A differ). Symmetric difference = in one but not both.
- In Java:
addAll(union),retainAll(intersection),removeAll(difference). - Those methods change the set itself, so copy first with
new HashSet<>(a). - HashSet: no order. LinkedHashSet: insertion order. TreeSet: sorted.
- (Extra) A ⊆ B when every value of A is in B. In Java:
b.containsAll(a)(bigger set first).
Next lesson: Maps and hashing, where you will see how a HashSet and HashMap find things so fast.
References
- Oracle, "Set (Java SE 21 & JDK 21)," "HashSet," and "TreeSet," Java API documentation. docs.oracle.com
- Oracle, "The Set Interface," The Java Tutorials. docs.oracle.com/javase/tutorial
- K. H. Rosen, Discrete Mathematics and Its Applications, 8th ed. McGraw-Hill, 2019, Section 2.2 (Set operations).