Arrays & Sets
Arrays & Sets
Arrays
An Array is an ordered collection of values of the same type. Arrays are zero-indexed and support random access.
// Creating arrays
var numbers = [1, 2, 3, 4, 5] // type inferred as [Int]
var names: [String] = ["Alice", "Bob"] // explicit type
var empty: [Int] = [] // empty array
var repeated = Array(repeating: 0, count: 5) // [0, 0, 0, 0, 0]
Accessing Elements:
let first = numbers[0] // 1
let slice = numbers[1...3] // [2, 3, 4]
let count = numbers.count // 5
let isEmpty = numbers.isEmpty // false
Adding and Removing:
numbers.append(6) // [1,2,3,4,5,6]
numbers.insert(0, at: 0) // [0,1,2,3,4,5,6]
numbers.remove(at: 0) // [1,2,3,4,5,6]
numbers.removeFirst() // [2,3,4,5,6]
numbers.removeLast() // [2,3,4,5]
Checking Containment:
numbers.contains(3) // true
numbers.firstIndex(of: 4) // Optional(2)
Sorting:
var scores = [90, 75, 88, 92, 85]
scores.sort() // [75, 85, 88, 90, 92]
scores.sorted(by: >) // [92, 90, 88, 85, 75]
scores.reverse() // reversed in place
Value Semantics
Arrays in Swift have value semantics. When you assign an array to another variable, it creates a copy (with copy-on-write optimization):
var a = [1, 2, 3]
var b = a
b.append(4)
print(a) // [1, 2, 3] — unchanged
print(b) // [1, 2, 3, 4]
Sets
A Set is an unordered collection of unique values. It provides O(1) membership testing and eliminates duplicates.
var fruits: Set<String> = ["apple", "banana", "apple"]
print(fruits) // {"apple", "banana"} — no duplicates
Set Operations:
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}
When to Use Sets:
- You need unique values
- You need fast membership testing (
containsis O(1) vs O(n) for arrays) - Order does not matter
let visitedPages: Set<String> = ["/home", "/about", "/home"]
visitedPages.count // 2 — duplicates removed
Choosing Between Array and Set
| Feature | Array | Set |
|---|---|---|
| Order | Preserved | Not guaranteed |
| Duplicates | Allowed | Not allowed |
| Lookup | O(n) | O(1) |
| Index access | Yes | No |
| Best for | Ordered data, indexing | Fast lookup, uniqueness |
Dictionaries
Dictionaries
A Dictionary is an unordered collection of key-value pairs. Each key is unique and maps to exactly one value.
// Creating dictionaries
var ages: [String: Int] = ["Alice": 30, "Bob": 25]
var empty: [String: Int] = [:]
Accessing Values:
let aliceAge = ages["Alice"] // Optional(30) — returns Optional
let unknown = ages["Zach"] // nil
Note: Dictionary subscript returns an optional because the key might not exist.
Adding and Removing:
ages["Charlie"] = 35 // add
ages["Alice"] = 31 // update
ages.removeValue(forKey: "Bob") // remove
ages["Bob"] = nil // also removes
Iteration:
for (name, age) in ages {
print("\(name) is \(age)")
}
for key in ages.keys {
print(key)
}
for value in ages.values {
print(value)
}
Convenience Initializers:
// From a sequence of key-value pairs
let pairs = [("a", 1), ("b", 2), ("c", 3)]
let dict = Dictionary(uniqueKeysWithValues: pairs)
Grouping:
let words = ["apple", "banana", "avocado", "blueberry"]
let grouped = Dictionary(grouping: words) { $0.prefix(1) }
// ["a": ["apple", "avocado"], "b": ["banana", "blueberry"]]
Merging:
var dict1 = ["a": 1, "b": 2]
let dict2 = ["b": 3, "c": 4]
dict1.merge(dict2) { (existing, _) in existing }
// ["a": 1, "b": 2, "c": 4]
Default Values:
var counts: [String: Int] = [:]
for word in ["hello", "world", "hello"] {
counts[word, default: 0] += 1
}
// ["hello": 2, "world": 1]
The default subscript is extremely useful for counting and accumulation patterns.
Higher-Order Functions
Higher-Order Functions
Swift collections support powerful higher-order functions that operate on each element, enabling functional programming patterns.
map
Transforms each element using a closure and returns a new array:
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 } // [2, 4, 6, 8, 10]
let names = ["alice", "bob"]
let capitalized = names.map { $0.capitalized } // ["Alice", "Bob"]
map is essential for transforming data from one shape to another. The output array always has the same count as the input.
filter
Selects elements that satisfy a condition (closure returns Bool):
let numbers = [1, 2, 3, 4, 5, 6]
let evens = numbers.filter { $0 % 2 == 0 } // [2, 4, 6]
let names = ["Alice", "Bob", "Amanda"]
let aNames = names.filter { $0.hasPrefix("A") } // ["Alice", "Amanda"]
The output array may have fewer elements than the input.
reduce
Combines all elements into a single value using an accumulator:
let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce(0) { $0 + $1 } // 15
let product = numbers.reduce(1, *) // 120
let words = ["Hello", " ", "World"]
let sentence = words.reduce("") { $0 + $1 } // "Hello World"
The first argument is the initial value (accumulator start). The closure receives the running total and the current element.
compactMap
Like map, but filters out nil results:
let strings = ["1", "2", "three", "4"]
let numbers = strings.compactMap { Int($0) } // [1, 2, 4]
// Without compactMap, map would produce [Optional(1), Optional(2), nil, Optional(4)]
compactMap is invaluable when working with optionals in collections.
Chaining
Higher-order functions can be chained for powerful data pipelines:
let result = (1...100)
.filter { $0 % 3 == 0 }
.map { $0 * $0 }
.reduce(0, +)
// Sum of squares of multiples of 3 from 1 to 100
Other Useful Functions
let numbers = [5, 3, 8, 1, 9]
numbers.min() // Optional(1)
numbers.max() // Optional(9)
numbers.contains(8) // true
numbers.allSatisfy { $0 > 0 } // true
numbers.forEach { print($0) } // prints each element
// sorted and sorted(by:)
numbers.sorted() // [1, 3, 5, 8, 9]
numbers.sorted(by: >) // [9, 8, 5, 3, 1]
// prefix, suffix, dropFirst, dropLast
numbers.prefix(3) // [5, 3, 8]
numbers.dropFirst() // [3, 8, 1, 9]
Performance Considerations
map,filter,reducecreate new arrays — consider lazy evaluation for large collectionscontainson an array is O(n); use aSetfor O(1) lookups- Chaining creates intermediate arrays; for performance-critical code, use a single
reduceorforloop
Higher-order functions make Swift code more expressive and declarative. Master these to write cleaner, more maintainable code.
Quiz
1. What is the difference between Array and Set?
2. What does `compactMap` do?
3. What does dictionary subscript return?
4. What is the initial value in `reduce(0) { $0 + $1 }`?
5. What does `["a", "b", "a"].count` return for a Set?
Flashcards
Question
What is the difference between `map` and `compactMap`?
Click to reveal answer
Answer
`map` transforms each element; `compactMap` transforms and removes nil results.
Question
When should you use a Set instead of an Array?
Click to reveal answer
Answer
When you need unique values or fast O(1) membership testing and order doesn't matter.
Question
What does `reduce` do?
Click to reveal answer
Answer
Combines all elements into a single value using an accumulator and a closure.
Question
How do you add a default value to a dictionary lookup?
Click to reveal answer
Answer
Use the default subscript: `dict[key, default: value]`
Question
What value semantics means for arrays?
Click to reveal answer
Answer
Assigning an array copies it (with copy-on-write). Mutating one does not affect the other.
Revision Notes
Key Takeaways
- 1. Arrays are ordered; Sets are unordered with unique elements
- 2. Dictionary subscript returns Optional; use default subscript for counting
- 3. map transforms, filter selects, reduce combines, compactMap filters nils
- 4. Collections have value semantics in Swift (copy-on-write)
- 5. Chain higher-order functions for expressive data pipelines
Interview Tips
- • Know the time complexity of Array vs Set for lookups
- • Explain when to use compactMap vs map
- • Be able to implement reduce manually
- • Understand dictionary grouping and merging patterns
Cheat Sheet
Collections Cheat Sheet
Arrays:
[Type]— ordered, duplicates allowed, O(n) lookupappend,insert,remove,contains,sorted
Sets:
Set<Type>— unordered, unique, O(1) lookupunion,intersection,subtracting
Dictionaries:
[Key: Value]— key-value pairs, O(1) lookup- Subscript returns Optional; use
default:for counting
Higher-Order Functions:
map { }— transform each elementfilter { }— keep elements matching conditionreduce(initial) { }— combine into single valuecompactMap { }— map + remove nils