# Swift Sets: How to Use Unordered Unique Collections

Source: https://devdocs10.com/articles/swift/swift-sets  
By Murat Bo · Published 2026-05-12 · DevDocs10 (https://devdocs10.com)

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.

- A set stores unique values.
- A set is unordered, so items do not have fixed positions like array indexes.
- All values in a set must be the same type.
- The type stored in a set must conform to `Hashable`.
- Sets support useful operations such as union, intersection, subtraction, and symmetric difference.

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:

- They make your intent obvious: duplicates are not allowed.
- They are excellent for membership checks such as “has this ID already been processed?”
- They provide clean built-in operations for comparing groups of values.
- They reduce bugs caused by accidentally storing the same item multiple times.

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

## 3. Basic Syntax

### Declaring a set

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

```swift
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.

```swift
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.

```swift
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.

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

Output (tested with Swift 6.4):

```text
["Paris", "Tokyo", "London"]
```

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.

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

let currentRole = "editor"

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

Output (tested with Swift 6.4):

```text
Access granted
```

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.

```swift
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)
```

Output (tested with Swift 6.4):

```text
["Chris", "Ben", "Ana", "Dana"]
["Ben"]
["Chris", "Ana"]
```

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.

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

print(uniqueScores)
```

Output (tested with Swift 6.4):

```text
[20, 30, 10]
```

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

- Tracking unique user IDs that have already been processed in a batch job.
- Storing selected categories, filters, or feature flags where each option should appear once.
- Checking whether a word belongs to a blocked-word list or allowed-word list.
- Comparing permissions assigned to users and groups with union or intersection.
- Removing duplicate values from imported data before further processing.
- Keeping a set of visited nodes or states in search algorithms and graph traversal.

## 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.

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

Output (tested with Swift 6.4):

```text
["Mia", "Liam", "Noah"]
Mia
```

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

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

Output (tested with Swift 6.4):

```text
["Liam", "Mia", "Noah"]
```

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'`.

```swift
struct Person {
    let name: String
}

let people: Set<Person> = []
```

**Fix:** Make the custom type conform to `Hashable`.

```swift
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.

```swift
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.

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

Output (tested with Swift 6.4):

```text
101
```

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.

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

Output (tested with Swift 6.4):

```text
1
```

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

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

Output (tested with Swift 6.4):

```text
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.

```swift
// 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.

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

Output (tested with Swift 6.4):

```text
["Networking", "Swift", "Testing"]
```

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.

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

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

Output (tested with Swift 6.4):

```text
["Testing"]
```

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

## 8. Limitations and Edge Cases

- Sets are unordered, so you should never rely on a particular print or iteration order.
- Set elements must conform to `Hashable`, including custom structs and enums.
- If you need duplicate values, a set is the wrong collection; use an array instead.
- If you need position-based access like `[0]`, convert the set to an array first.
- Converting an array to a set removes duplicates but also removes original ordering.
- Methods like `sorted()` return an array, not another set.
- When a set seems to be “not working,” the issue is often that you expected order, expected duplicates, or used a non-Hashable type.

## 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.

```swift
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())
```

Output (tested with Swift 6.4):

```text
User is subscribed to iOS
Subscribed topics: ["Backend", "Swift", "iOS"]
Matching featured topics: ["Backend", "Swift"]
Featured topics not yet subscribed: ["Testing"]
```

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

- A Swift `Set` stores unique values of the same type.
- Sets are unordered, so they are not a good choice when display order matters.
- Set element types must conform to `Hashable`.
- Common operations include `insert`, `remove`, `contains`, `union`, and `intersection`.
- Sets are often better than arrays for fast membership checks and duplicate prevention.
- Convert a set to a sorted array when you need predictable output.

## 11. Practice Exercise

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

- Start with at least three languages.
- Insert one new language.
- Try inserting a duplicate language.
- Check whether `"Swift"` exists in the set.
- Print the final set in sorted order.

**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()`.

```swift
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())
```

Output (tested with Swift 6.4):

```text
Swift is in the set
Sorted languages: ["Go", "JavaScript", "Python", "Swift"]
```

## 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.
