iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Sets

Swift Set is an unordered collection of unique, Hashable values. Fast membership, union/intersection/difference, and easy interop with Array.

Swift — Set

EXAMPLE
// ===== Creating a Set =====
var tags: Set<String> = ["vip", "beta", "vip"]   // duplicates collapse
print(tags)                                       // unordered

// From an array:
let arr = [1, 2, 2, 3, 4, 4, 5]
let unique = Set(arr)                             // [1, 2, 3, 4, 5]

// Type inference needs help when Swift can't tell:
let empty = Set<Int>()
let alsoEmpty: Set<Int> = []

// ===== Mutation =====
tags.insert("new")                                // (inserted: true, memberAfterInsert: "new")
tags.remove("beta")                               // returns the removed element, or nil
tags.removeAll()

// ===== Membership and counts =====
let s: Set = [1, 2, 3, 4]
s.contains(3)                                     // true
s.count                                           // 4
s.isEmpty                                         // false

// ===== Set algebra =====
let a: Set = [1, 2, 3, 4]
let b: Set = [3, 4, 5, 6]

a.union(b)              // [1, 2, 3, 4, 5, 6]
a.intersection(b)       // [3, 4]
a.subtracting(b)        // [1, 2]
a.symmetricDifference(b)// [1, 2, 5, 6]

// Relationships:
a.isSubset(of: [1,2,3,4,5])         // true
a.isStrictSubset(of: [1,2,3,4])     // false (equal isn't strict)
a.isSuperset(of: [1, 2])            // true
a.isDisjoint(with: [9, 10])         // true

// ===== In-place variants =====
var x: Set = [1, 2, 3]
x.formUnion([3, 4])                 // x is now [1,2,3,4]
x.formIntersection([2, 3, 9])       // x is now [2,3]
x.subtract([3])                     // x is now [2]

// ===== Custom Hashable types =====
struct User: Hashable {
    let id: UUID
    let name: String
    // Swift synthesises Hashable when all stored properties are Hashable.
}

var members: Set<User> = []
members.insert(User(id: UUID(), name: "Alex"))

// Override hash to consider only id:
struct UserById: Hashable {
    let id: UUID
    let name: String
    func hash(into hasher: inout Hasher) { hasher.combine(id) }
    static func == (l: Self, r: Self) -> Bool { l.id == r.id }
}

// ===== Iteration =====
for t in tags {
    print(t)        // unordered each time
}

// Sort to iterate stably:
for t in tags.sorted() {
    print(t)
}

// ===== Bridging =====
let arrayOut = Array(tags)        // ordering not guaranteed
let backToSet = Set(arrayOut)

// ===== Filter + map produce arrays; explicitly convert back =====
let evens = a.filter { $0 % 2 == 0 }           // [Int]
let evensSet = Set(evens)                       // Set<Int>

// ===== Patterns to internalise =====
// - Set for any 'distinct membership' collection (tags, ids, flags)
// - Use set algebra over manual loops: a.subtracting(b) beats nested for loops
// - Implement Hashable on identity-only types (override hash + ==) when storage uses ids
// - sorted() when iteration order matters; never rely on Set's order

// ===== Pitfalls =====
// - Treating a Set like an Array — Set has no [] subscript by index
// - Hash collisions caused by lazy/random hash impls -> rare but real on custom types
// - Reordering across runs (Hashable uses a per-process random seed) -> never persist Set iteration order
// - Mixing Hashable with reference types whose hash changes after insert -> 'lost' element

Why it matters

Set is the right tool more often than people remember: unique tags, ids, capability flags, anything where order does not matter. The algebra (union/intersection/subtracting) replaces nested loops with one-liners, and Hashable synthesis means you barely write any boilerplate.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
let tags: Set<String> = ["sql", "postgres", "sql"]
print(tags.contains("sql"))
Try it Yourself »

Discussion

Loading…