Skip to content
beginner Phase 1 · Swift Foundations

Collections

Work with Array, Set, Dictionary, and their mutable variants using map, filter, reduce, and functional operations.

50m
4 problems
Topic Progress 0%

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 (contains is 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, reduce create new arrays — consider lazy evaluation for large collections
  • contains on an array is O(n); use a Set for O(1) lookups
  • Chaining creates intermediate arrays; for performance-critical code, use a single reduce or for loop

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?

Question 1 options

2. What does `compactMap` do?

Question 2 options

3. What does dictionary subscript return?

Question 3 options

4. What is the initial value in `reduce(0) { $0 + $1 }`?

Question 4 options

5. What does `["a", "b", "a"].count` return for a Set?

Question 5 options

Flashcards

Question

What is the difference between `map` and `compactMap`?

Answer

`map` transforms each element; `compactMap` transforms and removes nil results.

Question

When should you use a Set instead of an Array?

Answer

When you need unique values or fast O(1) membership testing and order doesn't matter.

Question

What does `reduce` do?

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?

Answer

Use the default subscript: `dict[key, default: value]`

Question

What value semantics means for arrays?

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) lookup
  • append, insert, remove, contains, sorted

Sets:

  • Set<Type> — unordered, unique, O(1) lookup
  • union, intersection, subtracting

Dictionaries:

  • [Key: Value] — key-value pairs, O(1) lookup
  • Subscript returns Optional; use default: for counting

Higher-Order Functions:

  • map { } — transform each element
  • filter { } — keep elements matching condition
  • reduce(initial) { } — combine into single value
  • compactMap { } — map + remove nils