Swift Set Operations
Introduction
Sets in Swift are unordered collections of unique values. What makes sets particularly powerful are the mathematical operations you can perform on them. These operations allow you to efficiently compare and combine sets in ways that would be cumbersome with arrays.
In this tutorial, we'll explore Swift's built-in set operations:
- Union
- Intersection
- Subtraction
- Symmetric difference
We'll learn what each operation means, how to use it in Swift, and explore practical real-world applications.
What are Set Operations?
Set operations are methods that work with two or more sets to produce new sets based on the relationship between the elements. Think of them as mathematical functions applied to collections.
Let's start by creating some example sets to work with throughout this tutorial:
let programmers = Set(["Alice", "Bob", "Charlie", "Diana"])
let designers = Set(["Bob", "Eve", "Frank", "Diana"])
let managers = Set(["Charlie", "Grace", "Hannah"])
Union Operation
The union operation combines all elements from two sets into a single set. Any duplicates are automatically removed (as sets only contain unique elements).
Syntax
Swift provides two ways to create unions:
// Method 1: Using the union() method
let result1 = setA.union(setB)
// Method 2: Using the union operator (∪)
let result2 = setA.formUnion(setB) // Modifies setA
Example
Let's find all people in our organization:
let allEmployees = programmers.union(designers).union(managers)
print(allEmployees)
// Output: ["Diana", "Alice", "Hannah", "Bob", "Frank", "Grace", "Charlie", "Eve"]
// Note: Order may vary as sets are unordered
You can also use the formUnion
method to modify a set in place:
var teamMembers = programmers
teamMembers.formUnion(designers)
print(teamMembers)
// Output: ["Diana", "Alice", "Bob", "Frank", "Charlie", "Eve"]
Intersection Operation
The intersection operation creates a new set containing only the elements that appear in both sets.
Syntax
// Method 1: Using the intersection() method
let result1 = setA.intersection(setB)
// Method 2: Modifying in place
let result2 = setA.formIntersection(setB) // Modifies setA
Example
Let's find people who are both programmers and designers:
let programmersWhoDesign = programmers.intersection(designers)
print(programmersWhoDesign)
// Output: ["Diana", "Bob"]
// Who is both a programmer and a manager?
let programmingManagers = programmers.intersection(managers)
print(programmingManagers)
// Output: ["Charlie"]
Subtraction Operation
The subtraction operation (also called set difference) creates a new set with elements that are in the first set but not in the second set.
Syntax
// Method 1: Using the subtracting() method
let result1 = setA.subtracting(setB)
// Method 2: Modifying in place
let result2 = setA.subtract(setB) // Modifies setA
Example
Let's identify programmers who aren't designers:
let pureCoders = programmers.subtracting(designers)
print(pureCoders)
// Output: ["Alice", "Charlie"]
// Similarly, designers who aren't programmers:
let pureDesigners = designers.subtracting(programmers)
print(pureDesigners)
// Output: ["Eve", "Frank"]
Symmetric Difference
The symmetric difference operation creates a new set with elements that are in either set but not in both.
Syntax
// Method 1: Using the symmetricDifference() method
let result1 = setA.symmetricDifference(setB)
// Method 2: Modifying in place
let result2 = setA.formSymmetricDifference(setB) // Modifies setA
Example
Find people who are either programmers or designers, but not both:
let eitherProgrammerOrDesigner = programmers.symmetricDifference(designers)
print(eitherProgrammerOrDesigner)
// Output: ["Alice", "Eve", "Frank", "Charlie"]
Practical Applications
Let's explore some real-world scenarios where set operations are useful:
Managing Access Permissions
Imagine a system where users have different permission levels:
let admins = Set(["Alice", "Bob"])
let contentEditors = Set(["Bob", "Charlie", "Diana"])
let subscribers = Set(["Eve", "Frank", "Diana"])
// Who has any kind of access?
let allUsers = admins.union(contentEditors).union(subscribers)
// Who are admins but also edit content?
let adminEditors = admins.intersection(contentEditors)
// Who are subscribers only (no other roles)?
let pureSubscribers = subscribers.subtracting(admins.union(contentEditors))
print("All users:", allUsers)
// Output: All users: ["Frank", "Diana", "Alice", "Bob", "Charlie", "Eve"]
print("Admin-editors:", adminEditors)
// Output: Admin-editors: ["Bob"]
print("Pure subscribers:", pureSubscribers)
// Output: Pure subscribers: ["Frank", "Eve"]
Course Enrollment System
let mathStudents = Set(["Alice", "Bob", "Charlie"])
let physicsStudents = Set(["Bob", "Diana", "Eve"])
let chemistryStudents = Set(["Alice", "Eve"])
// Students taking at least one science course
let scienceStudents = physicsStudents.union(chemistryStudents)
// Students taking both math and any science
let mathAndScienceStudents = mathStudents.intersection(scienceStudents)
// Students taking math but no science
let mathOnlyStudents = mathStudents.subtracting(scienceStudents)
print("Science students:", scienceStudents)
// Output: Science students: ["Diana", "Alice", "Bob", "Eve"]
print("Math & science students:", mathAndScienceStudents)
// Output: Math & science students: ["Alice", "Bob"]
print("Math only students:", mathOnlyStudents)
// Output: Math only students: ["Charlie"]
Testing Set Relations
Swift also provides methods to test relationships between sets:
let setA = Set([1, 2, 3])
let setB = Set([1, 2])
let setC = Set([4, 5])
// Is setB a subset of setA? (Are all elements of B in A?)
print(setB.isSubset(of: setA)) // true
// Is setA a superset of setB? (Are all elements of B in A?)
print(setA.isSuperset(of: setB)) // true
// Do setA and setC have no elements in common?
print(setA.isDisjoint(with: setC)) // true
Performance Considerations
Set operations in Swift are highly optimized and typically run in O(n) time, where n is the size of the sets involved. This makes them much more efficient than equivalent operations on arrays when working with large collections.
For example, finding common elements between two arrays would require nested loops, resulting in O(n²) complexity, while set intersection is just O(n).
// Efficient way (using sets)
let arrayA = [1, 2, 3, 4, 5]
let arrayB = [3, 4, 5, 6, 7]
let setA = Set(arrayA)
let setB = Set(arrayB)
let commonElements = setA.intersection(setB)
print(commonElements) // [3, 4, 5]
Summary
Swift's set operations provide powerful ways to manipulate and analyze collections of unique values. These operations are:
- Union (
union
,formUnion
): Combines all elements from both sets. - Intersection (
intersection
,formIntersection
): Finds elements common to both sets. - Subtraction (
subtracting
,subtract
): Removes elements of one set from another. - Symmetric Difference (
symmetricDifference
,formSymmetricDifference
): Finds elements in either set but not both.
These operations are not just theoretical concepts—they have practical applications in permissions management, data analysis, and any situation where you need to compare or combine collections.
Exercises
-
Create sets representing movies watched by three friends. Find movies that all three have watched, and movies that only one person has watched.
-
Implement a basic tag filtering system for a blog, where articles have tags and users can filter by including or excluding specific tags.
-
Create a dictionary where keys are departments and values are sets of employees. Write functions to find:
- All employees in the company
- Employees who work in multiple departments
- Departments that have no employees in common
Additional Resources
Happy coding!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)