Swift by Notes Lesson 3-12
🧺 Lesson 3: Collections — Arrays, Sets, and Dictionaries
Welcome back!
In this lesson, we’re diving into the heart of data handling in Swift — collections.
You'll learn how to store, organize, and retrieve values using three essential types:
`Array`: for ordered lists
`Set`: for unique items
`Dictionary`: for key-value pairs
We’ll break down the differences between them, when to choose which type, and how to use their
most important features — like filtering, looping, and modifying contents.
These tools are everywhere — from storing user preferences, to mapping search results, to
organizing data in any app.
By the end of this lesson, you’ll be able to build flexible, reliable Swift structures for almost any use
case.
Let’s dive into the world of collections — and level up your Swift toolkit.
🧱 Core Swift Collections
Swift offers three main collection types:
Collection Ordered? Allows Duplicates? Access Type Example Syntax
`Array` ✅ Yes ✅ Yes By index `let a = [1, 2, 3]`
`Set` ❌ No ❌ No By membership `let s: Set = [1, 2, 3]`
`Dictionary` ❌ No Keys: ❌ Unique By key `let d = ["a": 1, "b": 2]`
✅ Quick Notes
Arrays preserve the order of insertion and allow repeated values
Sets are unordered and automatically eliminate duplicates
Dictionaries store key–value pairs, where keys must be unique
All three types are generic, meaning you can specify the types they hold:
`Array<Int>, Set<String>, Dictionary<String, Int>`
💬 Why This Matters
Many beginners confuse arrays and sets — or expect dictionaries to maintain order like arrays.
But making the wrong choice leads to subtle bugs, slower code, and confusing logic.
Here’s what happens if you don’t master this:
❌ You might sort a `Set` expecting order — but get unpredictable results
❌ You might try to access a `Dictionary` by index — which won’t work
❌ You might use an `Array` when a `Set` would make searching 10x faster
That’s why we cover this early — it sets the stage for choosing the right tool for every task.
🧪 Mini Challenge
Before we move on, can you guess the best type for each of the following?
Situation Best Collection
List of shopping items in cart `Array`
Situation Best Collection
Unique tags from blog posts `Set`
Mapping country codes to names `Dictionary`
History of viewed screens (in order) `Array`
Favorite genres (no repeats) `Set`
You can write your answer in a comments bellow this materials in our telegram channel
📚,🍿,🔑:🎁 When to Use Arrays, Sets, or Dictionaries
Choosing the right collection type is more than a syntax decision — it’s about building safe, fast, and
expressive code.
Let’s map the right tool to the right job.
💡 Situation ✅ Best Choice 🧠 Why?
Preserve order (e.g. steps in flow) `Array` Keeps items in exact sequence
Enforce uniqueness (e.g. tags) `Set` Automatically eliminates duplicates
Map keys to values (e.g. ID → name) `Dictionary` Provides direct access via unique keys
Predictable iteration order `Array` Indexable and linear
Check fast if item exists `Set` Optimized for hash-based membership
Store config values (e.g. "env": "prod") `Dictionary` Keys give semantic access to each setting
✅ Rule of Thumb
If order matters → use `Array`
If uniqueness matters → use `Set`
If you need to look up values by key → use `Dictionary`
🧪 Common Mistakes to Avoid
❌ Misuse ⚠️ Why It’s a Problem
Using `Array` for lookup Slow `O(n)` search vs `Set`/`Dictionary`
Using `Set` when order matters Set iteration is unordered
Assuming `Dictionary` keeps order No guarantee on key iteration order
Duplicates in `Array` when you meant unique Adds noise and bugs
🔍 Why This Matters
A lot of beginners default to `Array` for everything — but it’s not always the right tool.
Using a `Set` or `Dictionary` in the right place:
✅ Boosts performance (O(1) lookup vs O(n))
✅ Avoids duplication bugs
✅ Improves readability and intent
Once you internalize the differences, you’ll write faster, more idiomatic Swift — and spend less time
debugging weird collection behavior.
🧱 Declaring and Initializing Swift Collections
Before you can use collections, you need to know how to create them.
Let’s look at how to declare and initialize arrays, sets, and dictionaries with real data.
Swift gives you two ways to declare collections:
✅ With type inference — Swift figures out the type
✅ With explicit types — you declare the exact type
🔢 Arrays
let numbers = [1, 2, 3] // Inferred: Array<Int>
var names: [String] = ["Alice", "Bob"]
Use square brackets `[Type]`
Works great when order matters
`let` for constant lists, `var` if you’ll modify
🔠 Sets
let tags: Set = ["swift", "ios"] // Inferred: Set<String>
var uniqueInts: Set<Int> = [1, 2, 3]
Sets must use `Set<Type>`
Literal syntax works only if Swift can infer the type
Empty sets must be initialized with constructor syntax
🔑 Dictionaries
let ages = ["Alice": 30, "Bob": 25] // Inferred: [String: Int]
var config: [String: Bool] = ["darkMode": true]
Dictionaries use `[Key: Value]` format
Keys must be unique
Works well when each value has a label
🧩 Initializing Empty Collections
var emptyArray = [Int]() // or: Array<Int>()
var emptySet = Set<String>() // no literal allowed
var emptyDict = [String: Int]() // or: Dictionary<String, Int>()
“ 🎩 Why no literal for `Set`?
Because `{}` is reserved for closures and dictionaries — not sets.”
✅ Quick Rules
Collection Syntax Style Example Notes
Array `[Type]` `[String]`, `[Int]` Literal available
Set `Set<Type>` `Set<String>` Must use constructor for empty
Dictionary `[Key: Value]` `[String: Bool]` Key must be `Hashable`
🔍 Why This Matters
You’ll write collection declarations hundreds of times — for models, network data, and UI state.
One wrong syntax and your app won’t even compile.
That’s why Swift gives you both flexibility and clarity:
✅ Type inference keeps code clean
✅ Explicit types prevent mismatches
✅ Empty init forms help prepare variables before population
Knowing when to use each is a core skill in writing Swift code that compiles fast and works as
intended.
🔧 Mutating Swift Collections Safely
When your app’s data changes — a user adds a favorite, removes a tag, or updates a setting — you’ll
need to mutate collections.
But in Swift, mutation only works under the right conditions.
Let’s walk through how to safely add, update, and remove elements in arrays, sets, and dictionaries.
Arrays — Add, Update, Remove
var names = ["Anna"]
[Link]("Ben") // ➕ Add to the end
names[0] = "Alice" // 🔁 Update by index
[Link](at: 1) // ❌ Remove by index
⚠️
“ Index safety
Never modify by index without checking `.[Link](index)` — or you’ll crash.”
Sets — Insert and Remove
var tags: Set = ["swift"]
[Link]("ios") // ➕ Add (if not already present)
[Link]("swift") // ❌ Remove (if present)
“ 🎩 Prefer `.contains()` before removing
It avoids doing unnecessary work or triggering nil-based errors.”
Dictionaries — Add, Update, Remove
var scores = ["Bob": 90]
scores["Alice"] = 95 // ➕ Add or 🔁 Update
[Link](forKey: "Bob") // ❌ Remove
“ℹ Optional lookup
Accessing a dictionary value returns an optional — use `if let` to unwrap safely.
(we will cover optionals in a future lessons)”
if let score = scores["Alice"] {
print("Score is \(score)")
}
✅ Quick Mutation Rules
Collection Add Update Remove
`Array` `.append(value)` `array[index] = value` `.remove(at:)`
`Set` `.insert(value)` — (no update needed) `.remove(value)`
`Dictionary` `dict[key] = value` `dict[key] = newValue` `.removeValue(forKey:)`
🛑 You Must Use `var` to Mutate
All mutations only work if the collection is declared with `var`:
let list = [1, 2, 3]
[Link](4) // ❌
Compile error
✅ Knowledge Snapshot
✅ `var` collections are required for mutation
✅ `.append()`, `.insert()`, and `dict[key] = ...` are safe and expressive
✅ `.remove()` and `.removeValue(forKey:)` handle deletions
✅ Prefer checking with `.contains` or `if let` before mutating
✅ Collection types are value types — mutations create copies unless passed `inout`
🔍 When to Use `Set` Instead of `Array`
Arrays are the go-to for many Swift developers — but sometimes, they’re not the right choice.
If your goal is to avoid duplicates, check if something exists, or don’t care about order — a `Set`
might be exactly what you need.
Array vs Set: Key Differences
Feature `Array` `Set`
Keeps order ✅ Yes ❌ No (unordered)
Allows duplicates ✅ Yes ❌ No (unique values only)
Lookup time ❌ Slow (`O(n)`) ✅ Fast (`O(1)` with hashing)
Access by index ✅ Yes (`array[0]`) ❌ Not possible
Common use cases Ordered lists, history Tags, filters, seen items
✅ Choose `Set` When...
You want to enforce uniqueness
You care about fast membership tests
You don’t need to preserve order
var tags: Set = ["swift", "ios"]
[Link]("swift") // ❌
Won’t add duplicate
[Link]("ios") // ✅ Fast lookup
✅ Choose `Array` When...
You rely on order of insertion
You need to access elements by index
You allow repeated values
var steps = ["Open app", "Login", "Open app"]
print(steps[0]) // ✅
Access by index
⚠️ Common Pitfall
Using an `Array` when you really need a `Set` can lead to:
❌ Duplicate bugs
❌ Slow `contains()` performance
❌ Unclear code intent
Flip side? Using a `Set` when you care about order or indexing will bite you — you can’t control
order and can’t access elements by position.
🔍 Why This Matters
Many real-world lists — like `visitedIDs`, `selectedTags`, or `favoriteCategories` — don’t
require duplicates or ordering. But devs still reach for `Array` out of habit.
Knowing when to use `Set`:
✅ Prevents subtle bugs (like duplicates sneaking in)
✅ Improves performance on lookups and filters
✅ Shows intent clearly in your code
🔑 Using Dictionaries for Key–Value Mapping
Sometimes you don’t just want to store values — you want to label them.
That’s where dictionaries shine.
Swift’s `Dictionary` type lets you connect a unique key (like a name or ID) to a value (like a score or
setting).
A dictionary is like a mini database inside your code:
var phoneBook = ["Alice": "1234", "Bob": "5678"]
phoneBook["Alice"] // "1234" — read
phoneBook["Carol"] = "9999" // add new
phoneBook["Bob"] = "0000" // update existing
✅ Keys must be unique and hashable
✅ Values can be of any type
❌ Order is not guaranteed
“⚠️ What is `Hashable` in Swift?
A type that conforms to `Hashable` can be uniquely identified with a hash value, allowing it to
be used in sets or as dictionary keys. Swift automatically synthesizes `Hashable` for many
structs and enums.”
✅ Quick Rules for Dictionaries
Keys must be unique — last value wins on duplicate keys
Use `dict[key]` to access, add, or update values
Use `.removeValue(forKey:)` to delete
Values are returned as optionals — they might not exist
🧪 Example: Modeling Scores
var scores = [String: Int]()
scores["Alice"] = 95
scores["Bob"] = 87
scores["Alice"] = 100 // 🔁
Updates existing entry
if let score = scores["Alice"] {
print("Alice scored \(score)")
}
🔍 Why This Matters
Without dictionaries, you end up writing clunky logic like:
let ids = [101, 102]
let names = ["Alice", "Bob"]
Now you have to sync two arrays manually — and that’s a bug waiting to happen.
🛠 Functional Tools — `map`, `filter`, and `reduce`
Swift collections include powerful higher-order methods that let you transform, filter, and combine
data with clean, expressive syntax.
Before we dive inside this sub-theme, we need to have a quick look at the instrument called
for-in
🧾 Quick Note: `for-in` Loops in Swift
Swift’s `for-in` loop is a simple way to iterate over any collection — including arrays, sets,
dictionaries, and ranges.
✅ Basic Syntax
let names = ["Anna", "Ben", "Cara"]
for name in names {
print("Hello, \(name)!")
}
✅ `name` is a temporary variable for each element
✅ `names` is the collection being iterated
✅ Code inside the `{}` block runs once per item
🔁 Other Examples
With a `Set`:
let tags: Set = ["swift", "ios"]
for tag in tags {
print([Link]())
}
With a `Dictionary`:
let scores = ["Alice": 90, "Bob": 85]
for (name, score) in scores {
print("\(name): \(score)")
}
With a `Range`:
for i in 1...5 {
print("Step \(i)")
}
If you’ve ever written a `for` loop just to build a new array or sum values — there’s a better way,
and now we are ready to look at it.
🛠 Functional Building Blocks
🔄 `map` — Transform Each Element
let numbers = [1, 2, 3]
let squared = [Link] { $0 * $0 } // [1, 4, 9]
Applies a function to every element
Returns a new array with transformed values
🔍 `filter` — Keep Only What Matches
let even = [Link] { $0 % 2 == 0 } // [2]
Keeps only elements that match a condition
Perfect for selective lists
➕ `reduce` — Fold into a Single Value
let sum = [Link](0) { $0 + $1 } // 6
Combines all values into one (e.g., total, string join)
Initial value sets the base
📌 Works on Sets and Dictionaries Too
let tags: Set = ["swift", "ios"]
let uppercased = [Link] { $[Link]() }
// → ["SWIFT", "IOS"]
let scores = ["Alice": 80, "Bob": 95]
let allNames = [Link] { $[Link] } // ["Alice", "Bob"]
let total = [Link](0) { $0 + $[Link] } // 175
“ ⚠️ `map`, `filter`, and `reduce` return new collections — your original data stays intact.”
🧪 Why to choose these methods?
Using these methods makes your code:
✅ Shorter
✅ Safer (no index issues)
✅ Easier to read and maintain
Compare:
// Verbose
var result: [Int] = []
for n in numbers {
if n > 1 { [Link](n * 2) }
}
// Clean
let result = [Link] { $0 > 1 }.map { $0 * 2 }
✅ Summary Table
Method Purpose Returns Example Use Case
`map` Transform each element New collection Squaring numbers, formatting
Method Purpose Returns Example Use Case
`filter` Keep matching elements Subset Even numbers, valid entries
`reduce` Combine into single value Single result Sum, total, joined string
🔍 Why This Matters
A lot of Swift beginners rely on `for` loops for everything — but that leads to:
❌ Extra boilerplate
❌ Off-by-one bugs
❌ Mutable temporary arrays
Higher-order methods like `map`, `filter`, and `reduce`:
✅ Encourage declarative thinking
✅ Make your logic clear at a glance
✅ Are fully chainable and testable
Once you master them, your code gets faster to write — and easier to trust.
🔢 Accessing Collection Values Safely
To use collections, you need to get values out of them — either by index (arrays) or key
(dictionaries).
But if you get this wrong, your app can crash or misbehave.
Let’s learn the safe, Swift-native way to retrieve data.
Arrays — Index-Based Access
let fruits = ["Apple", "Banana", "Cherry"]
let first = fruits[0] // "Apple"
Accessing by index is fast — but unsafe if you go out of bounds:
let crash = fruits[99] // ❌ Runtime crash
✅ Safer version:
let i = 2
if [Link](i) {
print(fruits[i])
}
“ ⚠️ Prefer `.first`, `.last`, or optional binding when unsure of size”
🧾 Quick Note: Optional Binding in Swift
In Swift, optional binding lets you safely unwrap values that might be `nil` — such as the result of
accessing a dictionary key.
✅ Basic Syntax
if let value = someOptional {
// value is non-optional inside this block
print(value)
} else {
// the optional was nil
print("No value found")
}
🔑 Dictionaries — Key-Based Access
let ages = ["Anna": 30]
let anna = ages["Anna"] // ✅ Optional(30)
let tom = ages["Tom"] // ✅ nil (not present)
Because keys might not exist, you get back an optional — and must unwrap it:
if let age = ages["Tom"] {
print("Tom is \(age)")
} else {
print("No age found")
}
“ ⚠️ Optional access prevents crashes and encourages safe handling”
✅ Summary Snapshot
Collection Access Method Safe? What You Get
`Array` `array[index]` ❌ No Value or crash
`Set` Not indexable — Use `.contains()` instead
`Dictionary` `dict[key]` ✅ Yes `Optional<Value>`
👨🔧 Fixing Type Mismatches and Optional Errors in Collections
Working with collections in Swift is powerful — but also strict.
Swift’s type system and optional handling are designed to prevent bugs before your code even runs.
But that only helps if you understand what the compiler is telling you.
Let’s fix some of the most common mistakes.
❌ Common Mistake 1: Type Mismatch in Array
let numbers: [Int] = [1, 2, "3"] // ❌ Compile error
“`"3"` is a `String`, but the array expects `Int`”
✅ Fix:
let numbers: [Int] = [1, 2, 3] // ✅ All values are Int
❌ Common Mistake 2: Optional Dictionary Lookup
let dict = ["a": 1]
let value: Int = dict["b"] // ❌ Error: dict["b"] returns Int?
“You're trying to assign an `Int?` to a plain `Int`”
✅ Fix: Use optional binding or a default value
let value = dict["b"] ?? 0 // ✅ Uses fallback if key not found
❌ Common Mistake 3: Wrong Method on Set
var tags: Set<String> = ["swift"]
[Link]("ios") // ❌ 'Set' has no method 'append'
✅ Fix: Use `insert()` instead
[Link]("ios")
❌ Common Mistake 4: Unsafe Array Access
let list = [10, 20]
let item = list[5] // ❌ Index out of range crash
✅ Fix: Use index checking
if [Link](5) {
let item = list[5]
}
🧪 Time to Practice
You’ve just explored one of the most important areas of Swift: collections.
Arrays, sets, dictionaries, transformations, indexing, mutation — these tools are everywhere in real
apps.
Now it’s time to turn theory into real skill — by writing and running some Swift code.
I’ve prepared a practice file (`[Link]`) with a series of CLI-based multiple-choice
questions.
🎯 Just like before, it’s built to help you actively recall what you learned — which strengthens
memory and confidence far better than passive reading.
📦 Where to Get It
You’ll find the file in my Telegram channel:
👉 [Link]/swiftexplorer
Download `[Link]`, open your Terminal, and run it like this:
swift [Link]
“ ⚠️ This works even without creating an Xcode project — just run it directly from `.swift` like
in a previous lessons”
💡 Why This Helps
Practicing with code — even a small test — gives you:
✅ Real feedback on what you know
✅ A chance to catch and fix misunderstandings
✅ The feeling of actually using Swift, not just learning it
And if something trips you up — that’s a good thing!
It shows you exactly where to focus next.
📌 Head to the Telegram channel, grab the file, and give it a shot.
You’ve got this 💪
📱 Join the Community
You can always ask questions, share your progress, or just say hi:
Platform Link
Telegram 💬 [Link]
LinkedIn 💼 [Link]
⏭ What’s Next?
Now that you’ve mastered the fundamentals of collections — it’s time to learn how to control the
flow of your program.
Lesson 4: Control Flow — Conditions and Loops
You’ll learn:
How to use if, else, and switch (with `fallthrough`)
The differences between for-in, while, and repeat-while loops
How to write clean, readable logic using Swift’s control statements
🔁 How to break, continue, and fine-tune your loops
Whether you're responding to user input, filtering data, or running animations — control flow is
what brings your app to life.
Let’s make sure you know exactly how to structure your logic, loop efficiently, and write code that
flows.
📌 See you in the next lesson!
Powered by MarkdownToImage