Swift Arrays
Arrays are one of the most fundamental collection types in Swift. They store ordered lists of values of the same type, allowing you to efficiently organize and access related data elements. Whether you're building a simple to-do list or managing complex datasets, understanding arrays is essential for Swift programming.
What is an Array?
An array is an ordered collection of values of the same type. Think of it as a container that holds multiple items arranged in a specific sequence. Each item in an array has an index, starting from 0 for the first element.
Let's dive into working with Swift arrays:
Creating Arrays
Empty Arrays
You can create an empty array in several ways:
// Creating an empty array of strings
var emptyStringArray: [String] = []
// Alternative syntax using type annotation
var anotherEmptyArray = [String]()
// Using Array with type parameter
var yetAnotherEmptyArray = Array<String>()
Arrays with Initial Values
// Array literal syntax
let fruits = ["Apple", "Banana", "Orange", "Mango"]
// Array with repeated values
let fiveZeros = Array(repeating: 0, count: 5)
// Output: [0, 0, 0, 0, 0]
// Array with a range
let numbers = Array(1...5)
// Output: [1, 2, 3, 4, 5]
Accessing Array Elements
Individual Elements
Arrays are zero-indexed, meaning the first element is at index 0:
let fruits = ["Apple", "Banana", "Orange", "Mango"]
// Access first element
let firstFruit = fruits[0]
// Output: "Apple"
// Access third element
let thirdFruit = fruits[2]
// Output: "Orange"
Safe Access
Accessing an index out of bounds will crash your app. For safer access, use:
let fruits = ["Apple", "Banana", "Orange", "Mango"]
// Safe access using if statement
if fruits.indices.contains(4) {
let fruit = fruits[4]
} else {
print("Index out of bounds")
}
// Output: "Index out of bounds"
// Optional binding
let fifthFruit = fruits.indices.contains(4) ? fruits[4] : nil
// Output: nil
First and Last Elements
let fruits = ["Apple", "Banana", "Orange", "Mango"]
// First and last elements (returns optional)
let firstItem = fruits.first // "Apple"
let lastItem = fruits.last // "Mango"
Ranges of Elements
let fruits = ["Apple", "Banana", "Orange", "Mango", "Grapes", "Peach"]
// Get a slice of the array (creates ArraySlice)
let middleFruits = fruits[1...3]
// Output: ["Banana", "Orange", "Mango"]
// Convert slice to Array if needed
let middleFruitsArray = Array(fruits[1...3])
// Output: ["Banana", "Orange", "Mango"]
Modifying Arrays
Adding Elements
var fruits = ["Apple", "Banana", "Orange"]
// Append a single element
fruits.append("Mango")
// Output: ["Apple", "Banana", "Orange", "Mango"]
// Append multiple elements
fruits.append(contentsOf: ["Grapes", "Peach"])
// Output: ["Apple", "Banana", "Orange", "Mango", "Grapes", "Peach"]
// Insert at a specific position
fruits.insert("Strawberry", at: 1)
// Output: ["Apple", "Strawberry", "Banana", "Orange", "Mango", "Grapes", "Peach"]
Removing Elements
var fruits = ["Apple", "Banana", "Orange", "Mango", "Grapes"]
// Remove last element
let removedLast = fruits.removeLast()
// Output: "Grapes" (returns removed value)
// fruits is now ["Apple", "Banana", "Orange", "Mango"]
// Remove first element
let removedFirst = fruits.removeFirst()
// Output: "Apple" (returns removed value)
// fruits is now ["Banana", "Orange", "Mango"]
// Remove at specific index
let removedAtIndex = fruits.remove(at: 1)
// Output: "Orange" (returns removed value)
// fruits is now ["Banana", "Mango"]
// Remove all elements
fruits.removeAll()
// fruits is now []
// Remove all elements but keep capacity (better performance for reuse)
fruits.removeAll(keepingCapacity: true)
// fruits is now [] but capacity is preserved
Updating Elements
var planets = ["Mercury", "Venus", "Earth", "Mars"]
// Update single element
planets[1] = "Venus (Second Planet)"
// Output: ["Mercury", "Venus (Second Planet)", "Earth", "Mars"]
// Update a range of elements
planets[2...3] = ["Beautiful Earth", "Red Mars"]
// Output: ["Mercury", "Venus (Second Planet)", "Beautiful Earth", "Red Mars"]
// Replace a range with a different number of elements
planets[1...2] = ["New Planet"]
// Output: ["Mercury", "New Planet", "Red Mars"]
Array Properties and Methods
Basic Properties
let numbers = [10, 20, 30, 40, 50]
// Count elements
print("Array has \(numbers.count) elements")
// Output: "Array has 5 elements"
// Check if empty
print("Is array empty? \(numbers.isEmpty)")
// Output: "Is array empty? false"
// Get capacity
print("Current capacity: \(numbers.capacity)")
// Output will vary based on internal implementation
Finding Elements
let fruits = ["Apple", "Banana", "Orange", "Mango", "Apple"]
// Check if contains element
let hasOrange = fruits.contains("Orange") // true
// Find first index of an element
let firstAppleIndex = fruits.firstIndex(of: "Apple") // 0
// Find last index of an element
let lastAppleIndex = fruits.lastIndex(of: "Apple") // 4
// Find element meeting a condition
let longNameIndex = fruits.firstIndex(where: { $0.count > 5 }) // 1 (Banana)
Transforming Arrays
let numbers = [1, 2, 3, 4, 5]
// Map: transform each element
let squared = numbers.map { $0 * $0 }
// Output: [1, 4, 9, 16, 25]
// Filter: keep elements that satisfy a condition
let evenNumbers = numbers.filter { $0 % 2 == 0 }
// Output: [2, 4]
// Reduce: combine elements into a single value
let sum = numbers.reduce(0, +) // 15
let product = numbers.reduce(1, *) // 120
// CompactMap: transform and remove nil results
let strings = ["1", "2", "three", "4", "five"]
let parsedInts = strings.compactMap { Int($0) }
// Output: [1, 2, 4]
Sorting and Ordering
var fruits = ["Banana", "Apple", "Mango", "Orange"]
// Sort in place
fruits.sort()
// Output: ["Apple", "Banana", "Mango", "Orange"]
// Create sorted copy
let numbers = [3, 1, 4, 1, 5, 9]
let sortedNumbers = numbers.sorted()
// Output: [1, 1, 3, 4, 5, 9]
// Custom sorting
let sortedByLength = fruits.sorted { $0.count < $1.count }
// Output depends on string lengths
// Reverse
fruits.reverse()
// Output: ["Orange", "Mango", "Banana", "Apple"]
Iterating Over Arrays
For-in Loops
let fruits = ["Apple", "Banana", "Orange", "Mango"]
// Basic loop
for fruit in fruits {
print("I like \(fruit)")
}
// Output:
// I like Apple
// I like Banana
// I like Orange
// I like Mango
// Loop with indices
for (index, fruit) in fruits.enumerated() {
print("Fruit at index \(index) is \(fruit)")
}
// Output:
// Fruit at index 0 is Apple
// Fruit at index 1 is Banana
// Fruit at index 2 is Orange
// Fruit at index 3 is Mango
ForEach and Higher-Order Functions
let numbers = [1, 2, 3, 4, 5]
// forEach method
numbers.forEach { number in
print("\(number) squared is \(number * number)")
}
// Output:
// 1 squared is 1
// 2 squared is 4
// 3 squared is 9
// 4 squared is 16
// 5 squared is 25
Practical Examples
ToDo List App
// Simple ToDo list management
var todoList = ["Buy groceries", "Pay bills", "Call mom"]
// Add a new task
func addTask(_ task: String) {
todoList.append(task)
print("Task added: \(task)")
}
// Mark task as completed (remove from list)
func completeTask(at index: Int) -> String? {
guard index >= 0 && index < todoList.count else {
print("Invalid task index")
return nil
}
let completedTask = todoList.remove(at: index)
print("Completed: \(completedTask)")
return completedTask
}
// Usage
addTask("Clean room")
// Output: Task added: Clean room
completeTask(at: 1)
// Output: Completed: Pay bills
print("Remaining tasks: \(todoList.count)")
// Output: Remaining tasks: 3
Data Analysis
// Student scores analysis
let studentScores = [85, 92, 78, 65, 90, 76, 88, 95]
// Calculate average
let average = studentScores.reduce(0, +) / studentScores.count
print("Class average: \(average)")
// Output: Class average: 83
// Find highest score
if let highestScore = studentScores.max() {
print("Highest score: \(highestScore)")
}
// Output: Highest score: 95
// Count students who passed (score >= 70)
let passingCount = studentScores.filter { $0 >= 70 }.count
print("Number of students who passed: \(passingCount)")
// Output: Number of students who passed: 7
// Get letter grades
let letterGrades = studentScores.map { score -> String in
switch score {
case 90...: return "A"
case 80..<90: return "B"
case 70..<80: return "C"
case 60..<70: return "D"
default: return "F"
}
}
print("Letter grades: \(letterGrades)")
// Output: Letter grades: ["B", "A", "C", "D", "A", "C", "B", "A"]
Shopping Cart
struct CartItem {
let name: String
let price: Double
var quantity: Int
}
// Shopping cart implementation using arrays
class ShoppingCart {
var items: [CartItem] = []
func addItem(_ item: CartItem) {
// Check if item already exists
if let index = items.firstIndex(where: { $0.name == item.name }) {
items[index].quantity += item.quantity
} else {
items.append(item)
}
}
func removeItem(named name: String) {
items.removeAll(where: { $0.name == name })
}
func totalCost() -> Double {
return items.reduce(0) { total, item in
total + (item.price * Double(item.quantity))
}
}
func displayCart() {
print("Shopping Cart:")
for item in items {
print("- \(item.name): $\(item.price) × \(item.quantity) = $\(item.price * Double(item.quantity))")
}
print("Total: $\(totalCost())")
}
}
// Usage
let cart = ShoppingCart()
cart.addItem(CartItem(name: "Laptop", price: 999.99, quantity: 1))
cart.addItem(CartItem(name: "Mouse", price: 24.99, quantity: 2))
cart.addItem(CartItem(name: "Keyboard", price: 49.99, quantity: 1))
cart.displayCart()
// Output:
// Shopping Cart:
// - Laptop: $999.99 × 1 = $999.99
// - Mouse: $24.99 × 2 = $49.98
// - Keyboard: $49.99 × 1 = $49.99
// Total: $1099.96
Performance Considerations
When working with arrays, keep these performance aspects in mind:
-
Insertion/Deletion:
- Adding/removing elements at the end of an array is fast (O(1))
- Adding/removing elements at the beginning or middle requires shifting elements (O(n))
-
Searching:
- Linear search through unsorted arrays (O(n))
- Binary search if array is sorted (O(log n))
-
Memory:
- Arrays in Swift store elements contiguously in memory
- Arrays automatically grow capacity as needed, but can cause reallocation
For large arrays or performance-critical operations, consider using a different collection type like Set
or Dictionary
if appropriate.
Summary
Arrays are versatile collection types in Swift that allow you to:
- Store ordered collections of items of the same type
- Access elements by their position (index)
- Add, remove, and modify elements
- Iterate through elements in a predictable order
- Transform data using higher-order functions like
map
,filter
, andreduce
Mastering arrays is a fundamental step in becoming proficient with Swift, as they're used extensively in almost every application.
Exercises
To practice your understanding of Swift arrays, try these exercises:
- Create an array of your favorite books with at least 5 titles
- Write a function that finds the longest string in an array
- Implement a function that removes all duplicate elements from an array
- Create a shopping list app that allows adding, removing, and marking items as purchased
- Write code to reverse an array without using the built-in
reverse()
method
Additional Resources
- Swift Documentation: Array
- Swift By Sundell: Arrays
- Apple's Swift Programming Language Guide: Collection Types
Arrays form the foundation for more advanced Swift collections like sets and dictionaries, which we'll explore in upcoming sections.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)