Swift Sets: How to Use Unordered Unique Collections

Swift sets let you store unique values without caring about their order. They are useful when you need fast membership checks, want to prevent duplicates automatically, or need mathematical set operations like union and intersection. In this guide, you will learn what a Swift Set is, how to create and modify one, when to choose it over an array, and which beginner mistakes to avoid.

Quick answer: A Swift Set stores unique values of the same type in an unordered collection. Use it when duplicates should not exist and when checking whether a value exists matters more than preserving insertion order.

Difficulty: Beginner

Helpful to know first: basic Swift syntax, how variables and constants work, and simple collection types like arrays.

1. What Is Set?

A Set is a collection type in Swift that stores each value only once. If you try to add the same value again, the set still keeps only one copy.

This makes sets ideal for things like tags, unique usernames already seen, selected options, or fast lookup tables.

Beginners often compare Set with Array. The short version is simple: arrays keep order and allow duplicates, while sets remove duplicates and do not guarantee order. That difference affects how you read, display, and update the collection.

2. Why Set Matters

Sets solve a very common problem: storing values that should appear only once. If you used an array for the same job, you would often need extra checks before appending values, or you would need to remove duplicates later.

Sets also matter for performance and clarity:

You should not use a set when display order matters, when you need element positions, or when repeated values are meaningful.

3. Basic Syntax or Core Idea

Declaring a set

You can create a set by writing Set<Type> and assigning values in square brackets.

var fruits: Set<String> = ["Apple", "Banana", "Orange"]

This creates a set of strings. Even though the syntax uses square brackets like an array literal, the declared type tells Swift that this is a set.

Creating an empty set

For an empty set, you must be explicit about the type.

var numbers = Set<Int>()

This creates an empty set of integers. Swift needs the type because [] by itself is ambiguous.

Inserting, checking, and removing values

The most common set operations are adding, checking, and removing items.

var colors: Set<String> = ["Red", "Blue"]

colors.insert("Green")
let hasBlue = colors.contains("Blue")
colors.remove("Red")

This code adds a value, checks whether one exists, and removes another. These operations are the core of everyday set usage.

4. Step-by-Step Examples

Example 1: Preventing duplicates automatically

A set automatically ignores repeated values.

let cities: Set<String> = ["London", "Paris", "London", "Tokyo"]
print(cities)

Even though "London" appears twice in the literal, the set stores it once. This is one of the main reasons to use a set.

Example 2: Checking whether a value exists

Sets are especially useful when your code frequently asks whether something is present.

let allowedRoles: Set<String> = ["admin", "editor", "viewer"]

let currentRole = "editor"

if allowedRoles.contains(currentRole) {
print("Access granted")
} else {
print("Access denied")
}

This example checks membership clearly and directly. A set communicates that the values represent a group of allowed unique options.

Example 3: Using set operations

Swift sets support mathematical operations that are very useful in real applications.

let teamA: Set<String> = ["Ana", "Ben", "Chris"]
let teamB: Set<String> = ["Ben", "Dana"]

let allMembers = teamA.union(teamB)
let sharedMembers = teamA.intersection(teamB)
let onlyInA = teamA.subtracting(teamB)

print(allMembers)
print(sharedMembers)
print(onlyInA)

Here, union combines all unique values, intersection finds shared values, and subtracting finds values that exist only in the first set.

Example 4: Removing duplicates from an array

A common practical use is converting an array to a set to remove repeated values.

let scores = [10, 20, 10, 30, 20]
let uniqueScores = Set(scores)

print(uniqueScores)

This creates a set from the array, leaving only unique values. Remember that the result is unordered, so it is not a drop-in replacement for an array when order matters.

5. Practical Use Cases

6. Common Mistakes

Mistake 1: Expecting a set to keep insertion order

Many beginners treat a set like an array and expect values to stay in the order they were added.

Problem: A Swift set is unordered, so the printed order and iteration order are not guaranteed. Code that depends on a specific sequence can behave unpredictably.

let names: Set<String> = ["Mia", "Noah", "Liam"]
print(names)
print(names.first!)

Fix: If you need a stable order, convert the set to an array and sort it, or use an array from the start.

let names: Set<String> = ["Mia", "Noah", "Liam"]
let sortedNames = names.sorted()
print(sortedNames)

The corrected version works because sorting creates a predictable ordered result.

Mistake 2: Trying to store a non-Hashable type in a set

Every value in a Swift set must conform to Hashable. Custom types do not always do this automatically.

Problem: If the element type is not Hashable, Swift cannot determine uniqueness correctly, and you may see an error such as Type 'Person' does not conform to protocol 'Hashable'.

struct Person {
let name: String
}

let people: Set<Person> = []

Fix: Make the custom type conform to Hashable.

struct Person: Hashable {
let name: String
}

let people: Set<Person> = []

The corrected version works because Swift can now hash and compare each Person value.

Mistake 3: Using array-style indexing with a set

A set does not provide integer indexes like an array.

Problem: Code such as set[0] does not work because sets are unordered collections and do not support positional access.

let ids: Set<Int> = [101, 102, 103]
print(ids[0])

Fix: Iterate over the set, use membership checks, or convert it to a sorted array if you need index-based access.

let ids: Set<Int> = [101, 102, 103]
let sortedIDs = ids.sorted()
print(sortedIDs[0])

The corrected version works because the sorted array supports integer indexing.

Mistake 4: Thinking insert always adds a new value

If a value already exists, inserting it again does not create a duplicate.

Problem: Assuming a repeated insert creates another copy can lead to incorrect counts and logic errors.

var tags: Set<String> = ["swift"]
tags.insert("swift")
print(tags.count)

Fix: Remember that a set keeps one copy of each value. If duplicate entries matter, use an array instead.

var tags: Set<String> = ["swift"]
tags.insert("swift")
print(tags.count) // still 1

The corrected understanding works because sets enforce uniqueness automatically.

7. Best Practices

Use a set when uniqueness is part of the requirement

If duplicates should never exist, a set is more expressive than an array with manual duplicate checks.

// Less preferred: manual duplicate check in an array
var usernames = [String]()
let newName = "sam"
if !usernames.contains(newName) {
usernames.append(newName)
}

// Preferred: store unique names in a set
var uniqueUsernames = Set<String>()
uniqueUsernames.insert(newName)

This is cleaner because the collection itself enforces the rule.

Sort a set before presenting values to users

Since sets are unordered, user-facing output should usually be converted to a sorted array.

let topics: Set<String> = ["Networking", "Swift", "Testing"]
let displayTopics = topics.sorted()
print(displayTopics)

This gives users a predictable and readable order.

Use set operations instead of manual loops when comparing groups

Built-in operations are usually easier to read and less error-prone than custom comparison logic.

let requiredSkills: Set<String> = ["Swift", "Git", "Testing"]
let candidateSkills: Set<String> = ["Swift", "Git"]

let missingSkills = requiredSkills.subtracting(candidateSkills)
print(missingSkills)

This approach clearly shows the intent: find what is missing from one group compared with another.

8. Limitations and Edge Cases

9. Practical Mini Project

Let’s build a small example that tracks newsletter subscriptions by topic. A user can subscribe to topics only once, and we can compare their subscriptions against featured topics.

var subscribedTopics: Set<String> = ["Swift", "iOS"]

// Add new subscriptions
subscribedTopics.insert("Backend")
subscribedTopics.insert("Swift") // duplicate, ignored

// Check a subscription
if subscribedTopics.contains("iOS") {
print("User is subscribed to iOS")
}

// Compare with featured topics
let featuredTopics: Set<String> = ["Swift", "Testing", "Backend"]
let matchingTopics = subscribedTopics.intersection(featuredTopics)
let missingFeaturedTopics = featuredTopics.subtracting(subscribedTopics)

print("Subscribed topics:", subscribedTopics.sorted())
print("Matching featured topics:", matchingTopics.sorted())
print("Featured topics not yet subscribed:", missingFeaturedTopics.sorted())

This mini project shows several strengths of sets in one place: duplicates are prevented automatically, membership checks are simple, and comparing groups of values is concise.

10. Key Points

11. Practice Exercise

Create a Swift program that stores a set of favorite programming languages. Then:

Expected output: The duplicate should not appear twice, the membership check should print whether Swift exists, and the displayed list should be sorted.

Hint: Use Set<String>, then call insert, contains, and sorted().

var languages: Set<String> = ["Swift", "Python", "JavaScript"]

languages.insert("Go")
languages.insert("Swift")

if languages.contains("Swift") {
print("Swift is in the set")
} else {
print("Swift is not in the set")
}

print("Sorted languages:", languages.sorted())

12. Final Summary

Swift sets are a simple but powerful collection type for storing unique values. They are especially useful when duplicates should never exist, when you need to ask whether a value is present, or when you want to compare groups with operations like union and intersection.

The most important thing to remember is that sets are unordered. If you need index-based access or stable display order, use an array or convert the set to a sorted array before presenting the data. Once you are comfortable with sets, a good next step is learning how they compare in practice with Swift arrays and dictionaries so you can choose the right collection type for each problem.