Chapter 40: Swift Arrays: Multidimensional
1. What is a Multidimensional Array?
A multidimensional array is simply an array of arrays.
In other words:
- You have an outer array
- Each element of the outer array is itself an array
- So you access elements using two (or more) indices
Real-life analogies:
- 2D array → chessboard (8 rows × 8 columns)
- 2D array → monthly calendar (weeks as rows, days as columns)
- 2D array → spreadsheet table (rows and columns)
- 3D array → stack of chessboards, or RGB image (height × width × color channels)
In Swift we usually talk about 2D arrays (most common), sometimes 3D, and rarely more.
2. Creating a 2D Array — all common ways
Way 1 – Literal syntax (most readable for small fixed data)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
let matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] // Access: row 1 (second row), column 2 (third number) print(matrix[1][2]) // 6 |
Way 2 – Empty 2D array with fixed rows & columns
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let rows = 4 let columns = 5 var grid = Array(repeating: Array(repeating: 0, count: columns), count: rows) // Now grid is: // [ [0,0,0,0,0], // [0,0,0,0,0], // [0,0,0,0,0], // [0,0,0,0,0] ] |
Way 3 – From existing data (very common)
|
0 1 2 3 4 5 6 7 8 9 10 |
let sales2024 = [ ["Jan", "Feb", "Mar", "Apr"], [12000, 15000, 18000, 14000], [13000, 16000, 19000, 14500] ] |
3. Reading from a 2D Array
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
let chessBoard = [ ["♜", "♞", "♝", "♛", "♚", "♝", "♞", "♜"], ["♟", "♟", "♟", "♟", "♟", "♟", "♟", "♟"], [" ", " ", " ", " ", " ", " ", " ", " "], [" ", " ", " ", " ", " ", " ", " ", " "], [" ", " ", " ", " ", " ", " ", " ", " "], [" ", " ", " ", " ", " ", " ", " ", " "], ["♙", "♙", "♙", "♙", "♙", "♙", "♙", "♙"], ["♖", "♘", "♗", "♕", "♔", "♗", "♘", "♖"] ] // Piece at row 0, column 4 (black king) print(chessBoard[0][4]) // ♚ // White pawn at row 6, column 3 print(chessBoard[6][3]) // ♙ |
Safe access (very important)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
func safeGet<T>(array: [[T]], row: Int, col: Int) -> T? { guard row >= 0, row < array.count, col >= 0, col < array[row].count else { return nil } return array[row][col] } print(safeGet(array: chessBoard, row: 0, col: 4) ?? "Empty") // ♚ print(safeGet(array: chessBoard, row: 10, col: 5) ?? "Empty") // Empty |
4. Modifying a 2D Array (only if var)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var scores = [ [85, 92, 78], [88, 95, 90], [76, 82, 87] ] // Change value scores[1][2] = 99 // second row, third column → 90 → 99 // Add new row scores.append([80, 85, 88]) // Add new column to every row (careful!) for i in 0..<scores.count { scores[i].append(0) // add 0 as default } |
5. Looping over 2D Arrays — most common patterns
Pattern 1 – Nested for-in (classic & clear)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
let matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] print("Matrix:") for row in matrix { for number in row { print(number, terminator: " ") } print() // new line after each row } |
Output:
|
0 1 2 3 4 5 6 7 8 |
1 2 3 4 5 6 7 8 9 |
Pattern 2 – With row & column indices
|
0 1 2 3 4 5 6 7 8 9 10 |
for (rowIndex, row) in matrix.enumerated() { for (colIndex, value) in row.enumerated() { print("Position [\(rowIndex),\(colIndex)] = \(value)") } } |
Pattern 3 – Using indices
|
0 1 2 3 4 5 6 7 8 9 10 11 |
for rowIndex in matrix.indices { for colIndex in matrix[rowIndex].indices { print(matrix[rowIndex][colIndex], terminator: " ") } print() } |
6. Real-Life Examples You Will Actually Write
Example 1 – Monthly sales table
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
let months = ["Jan", "Feb", "Mar", "Apr"] let products = ["Phone", "Laptop", "Tablet"] let sales: [[Int]] = [ [120, 150, 180], // Phone sales per month [45, 60, 55], // Laptop [80, 95, 110] // Tablet ] print("Monthly Sales (₹000s)") print(" " + months.joined(separator: " ")) for (productIndex, productSales) in sales.enumerated() { let row = "\(products[productIndex]) " + productSales.map { String(format: "%4d", $0) }.joined(separator: " ") print(row) } |
Example 2 – Tic-tac-toe board
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
var board = [ [" ", " ", " "], [" ", " ", " "], [" ", " ", " "] ] // Place X in center board[1][1] = "X" // Place O in corner board[0][0] = "O" // Print board for row in board { print(row.joined(separator: " | ")) print("---------") } |
7. Very Common Beginner Mistakes & Correct Habits
| Mistake | Wrong / Dangerous code | Correct / Safe habit | Why? |
|---|---|---|---|
| Forgetting outer array can be empty | matrix[0][0] without check | guard !matrix.isEmpty else { … } | Crash if no rows |
| Assuming all rows have same length | matrix[row][col] without check | if col < matrix[row].count { … } | Rows can have different lengths |
| Force-unwrapping first/last of inner array | matrix[0].first! | matrix[0].first ?? default | Inner array can be empty |
| Modifying let array | let grid = …; grid[0][0] = 99 | Use var if you need to change | Immutable |
| Using fixed indices without validation | matrix[5][5] | Use indices.contains or safe subscript | Out-of-bounds → crash |
8. Quick Reference – Most Useful 2D Array Operations
| Goal | Recommended code | Notes |
|---|---|---|
| Create empty 2D grid | Array(repeating: Array(repeating: 0, count: cols), count: rows) | Classic way |
| Safe element access | matrix[safe: row]?[safe: col] ?? default | With safe subscript extension |
| Loop with row & column indices | for r in matrix.indices { for c in matrix[r].indices { … } } | Most explicit & safe |
| Print nicely | matrix.map { $0.map(String.init).joined(separator: ” “) }.joined(separator: “\n”) | Quick debug print |
| Get row | matrix[2] | Returns Array (copy) |
| Get column (trickier) | (0..<matrix.count).map { matrix[$0][col] } | No built-in column access |
9. Small Practice – Try these
- Create a 4×5 grid filled with zeros → Set position [1][2] = 99 → Print the grid row by row
- Create a 3×3 tic-tac-toe board → Place “X” in center → Place “O” in all four corners → Print the board with nice separators
- Create a sales table (3 products × 4 months) → Print it like a real table with headers
Paste your code here if you want feedback or cleaner versions!
What would you like to explore next about arrays?
- Sorting 2D arrays (by row, by column, custom)
- Transposing a matrix (rows ↔ columns)
- Flattening 2D → 1D and vice versa
- Multidimensional arrays in SwiftUI (grids, tables)
- Arrays vs ArraySlice vs ContiguousArray
- Or move to another topic (dictionaries, sets, optionals…)
Just tell me — we’ll keep going in the same clear, detailed, patient style 😊
