In Swift 5.8 arrays are collections that store elements and expand automatically when additional elements are added. Arrays contain elements of one type.
We can loop over elements in an array with the for
-loop, and access elements with a subscript. Most nontrivial Swift programs use arrays.
First, we create an empty String
array. We then append()
three string
literals to the array. After the appends, the count of the array is now 3.
var
keyword to declare the array. This is a variable array, which means it can be changed.print()
we display the array count and the array's contents. An array can be displayed in full this way.// Create an empty array and add three elements to it. var languages = [String]() languages.append("Swift") languages.append("Python") languages.append("Java") // Display count of the array. print(languages.count) // Print the array contents. print(languages)3 ["Swift", "Python", "Java"]
For
-in loopAn array can be looped over with the for-in
loop. This provides a clear syntax for getting each element in the array. Here we use a for-in
loop on an Int
array.
for-in
loop is clearer when we do not need to access the indexes of an array.// Create an Int array. var ids = [Int]() ids.append(10) ids.append(20) ids.append(30) // Loop over and print all Ints. for id in ids { print(id) }10 20 30
A shorter syntax form can be used to initialize an array. This requires only one line to declare (and place values in) the array.
// Create variable Int array with three values. var sizes: [Int] = [5, 10, 15] // Append another Int. sizes.append(20) print("Sizes: \(sizes)")Sizes: [5, 10, 15, 20]
Sometimes we want to get indexes and values in a single loop. The enumerated
method is useful for this. Here we use enumerated()
on a string
array.
enumerated()
to get indexes and values in an elegant way.var birds = ["finch", "sparrow", "eagle"] // Use enumerated() on the string array. for (index, value) in birds.enumerated() { // Display indexes and values. print("\(index) = \(value)") }0 = finch 1 = sparrow 2 = eagle
With the let
-keyword we declare a constant. When we create an array with let, we cannot call append (or other mutating methods) on the array.
var
" instead of let.// With let an array is constant. // ... We cannot append to it. let codes: [String] = ["x", "r", "w"] codes.append("t")/Users/.../main.swift:4:1: Immutable value of type '[String]' only has mutating members named 'append'
Often we want to get the first and last elements in an array. In Swift we can access the "first" and "last" properties of the array. These return optionals.
nil
to ensure they exist. They do not exist in an empty 0-element array.let cars: [String] = ["truck", "coupe", "sedan"] // Access first and last optional elements. // ... Test them against nil before using them. if cars.first != nil { print(cars.first!) } if cars.last != nil { print(cars.last!) }truck sedan
Here we use indexes to get the first and last elements in an array. The first element is at index 0, and the last element is at the count minus one.
// Create a String array with three elements. let pets: [String] = ["dog", "cat", "bird"] // Get first element. print(pets[0]) // Get last element. print(pets[pets.count - 1])dog bird
PopLast
This method removes the last element from an array and returns the element wrapped in an Optional
type. We can use "if let" to safely get the popped elements.
var names = ["bird", "fish"] // Get last element with popLast. if let last = names.popLast() { print("A", last) } if let last = names.popLast() { print("B", last) } if let last = names.popLast() { // This is not reached, but no error is caused. print("C", last) }A fish B bird
isEmpty
An array with zero elements is empty. The isEmpty
method will return true if the count is equal to 0. After an element is added, isEmpty
will no longer return true.
// Create an empty birds array. var birds: [String] = [] // The array is empty. if birds.isEmpty { print(true) } // Append an element so that the array is no longer empty. birds.append("parrot") if !birds.isEmpty { print(false) }true false
Contains
Does an element exist within an array? To find this out, we use a for-in
loop with an if
-statement. We return true from contains()
if a matching value is found in the array.
contains()
func
returns early if a match is found. This avoids processing the entire array.var animals: [String] = ["bird", "frog", "elephant"] // Determine if this string exists in the array. if animals.contains("bird") { print(true) } // This string does not exist. if !animals.contains("diamond") { print(false) }true false
Contains
, whereThe contains func
can be used with a "where" func
. The func
receives an element of the array's element type, and returns a Bool that indicates matching.
func colorStartsWithG(value: String) -> Bool { // Check for first letter. return value[value.startIndex] == "g" } func colorStartsWithX(value: String) -> Bool { return value[value.startIndex] == "x" } // A simple array. let colors = ["blue", "red", "green"] // Simple contains. if colors.contains("red") { print("CONTAINS RED") } // Use special funcs with contains. if colors.contains(where: colorStartsWithG) { print("CONTAINS COLOR STARTING WITH G") } if !colors.contains(where: colorStartsWithX) { print("DOES NOT CONTAIN COLOR STARTING WITH X") }CONTAINS RED CONTAINS COLOR STARTING WITH G DOES NOT CONTAIN COLOR STARTING WITH X
When accessing elements by index, we must be careful to have a valid index. We can test the count before using an index. Here we see the "index out of range" error.
let plants: [String] = ["tree", "fern", "bush"] print(plants[999])fatal error: Array index out of range (lldb)
An array can be created with repeating and count arguments. Repeating is the default fill value. The count is the total number of elements to create.
// Create an array with 10,000 elements. // ... Specify repeating and count. var x: [Int] = Array(repeating: 0, count: 10000) // Assign elements in array. x[0] = 1 x[9999] = 2 x[100] = 3 // Write array contents and size. print(x[0]) print(x[9999]) print(x[100]) print(x[1]) // Default is 0. print(x.count)1 2 3 0 10000
Append
arraysSometimes we need to append many values at once to an array. We can append new arrays in Swift to append each element individually.
// Create an Int array. var indexes = [10, 11, 12] // Append three Int elements at once. // ... The elements in the brackets are added individually. indexes += [20, 21, 22] // Display the result array. for element in indexes { print(element) }10 11 12 20 21 22
In Swift we can add two arrays together with the plus operator. The resulting array has all the individual elements from both arrays (including duplicates).
let
-keyword. We are not modifying array1 or array2 when we create a new array.// Two constant arrays with 2 elements each. let array1 = ["cat", "bird"] let array2 = ["fish", "plant"] // Combine the two arrays (add them together). let combined = array1 + array2 // Print the combined array count and elements. print(combined.count) print(combined)4 ["cat", "bird", "fish", "plant"]
Remove
atWe can remove elements from a Swift array by specifying an index. These are zero-based indexes, so 0 removes the first element, and 1 removes the second element.
Dictionary
is a data structure that makes removal faster. In a linear array, removal often causes shifting of elements.var ids = [10, 20, 300, 5000] print(ids) // Remove element at index 2 (the third element, 300). ids.remove(at: 2) print(ids) // Remove element at index 0 (the first element, 10). ids.remove(at: 0) print(ids)[10, 20, 300, 5000] [10, 20, 5000] [20, 5000]
RemoveLast
In a linear collection, removing the last element is often fast—no elements need to be shifted forward after the removal. Swift provides an optimized removeLast
.
var languages = ["Swift", "Java", "C#", "Go"] print(languages) // Remove the last element in the array. languages.removeLast() print(languages)["Swift", "Java", "C#", "Go"] ["Swift", "Java", "C#"]
In Swift we often use ranges to address collections. We can change a range of elements in an array. Here we change the elements at indexes 0 through 2 inclusive.
var years = [1999, 2000, 2001, 2015, 2017] // Replace elements at indexes 0, 1 and 2. // ... Replace 3 elements with 2 elements. years[0...2] = [2002, 2005] // Display result. print(years)[2002, 2005, 2015, 2017]
Insert
atAn element can be inserted into an array. This will cause the following elements to shift forward one to accommodate the new value. So this operation may be slow.
insert()
is the element to insert. The second argument, specified with "at," is the target index.var letters = ["A", "X", "Z"] print(letters) // Insert the letter C at index 1 (after the first element). letters.insert("C", at: 1) print(letters)["A", "X", "Z"] ["A", "C", "X", "Z"]
An array can be passed as an argument to a func
. We must specify the type of the array (its element type in square brackets). An array can also be returned.
String
array in the validate func
. We use a guard to ensure the first string
element has a specific value.func validate(animals: [String]) { // Test first element of string argument. guard animals.first == "ant" else { print("Error") return } print("OK") } let animals = ["ant", "fish", "hamster"] // Pass a string array as an argument. validate(animals: animals)OK
An array that is received as a parameter cannot be modified. It is constant. We first copy the array and then we can modify an array parameter.
func modify(values: [Int]) { // This func receives an array. // ... It adds to a copy of the array. var copy = Array(values) copy.append(10) copy.append(20) copy.append(30) print("Modify count: \(copy.count)") } // The array has 3 elements. let numbers = [0, 1, 2] print(numbers.count) // Call the func. modify(values: numbers) // The array still has only 3 elements. print("Numbers: \(numbers)")3 Modify count: 6 Numbers: [0, 1, 2]
FirstIndex
With this method we get the index of an element with a certain value. An Optional
Int
is returned. We can use optional binding (if let) to safely get the index.
indexOf
method.let letters = ["aa", "bb", "cc"] // Use index with an argument. if let index1 = letters.firstIndex(of: "bb") { print(index1) } if let index2 = letters.firstIndex(of: "nonexistent") { print(index2) } // See if the string exists in the array. // ... Use its index to print the value from the array. if let index3 = letters.firstIndex(of: "cc") { print(letters[index3]) }1 cc
An array has indices—these are the values like 0, 1 and 2 that we use to index the first, second and third elements. With the indices property, we can loop over these values.
let sizes = ["small", "medium", "large"] // Get in dice so far ray. // ... Access each element. for i in sizes.indices { print("\(i) / \(sizes[i])") }0 / small 1 / medium 2 / large
ElementsEqual
This method compares each element in one collection to another. Here we see that two of the arrays are equal, but the third one is not.
let numbers1 = [10, 100, 2000] let numbers2 = [10, 100, 2000] let numbers3 = [10, 0, 2000] // Use elementsEqual to compare entire arrays. if numbers1.elementsEqual(numbers2) { print("EQUAL") } if !numbers1.elementsEqual(numbers3) { print("NOT EQUAL") }EQUAL NOT EQUAL
The elements in an array come in a certain order. We can reverse this with the reversed()
method. Here we use reversed()
and then enumerated()
to display our inverted array.
var numbers = [10, 100, 2000] // Reverse the numbers. var inverted = numbers.reversed() // Display reversed numbers. for pair in inverted.enumerated() { print(pair) }(0, 2000) (1, 100) (2, 10)
CompactMap
This method transforms each element in a collection based on a mapping function. The func
passed to compactMap
must receive and return the element type.
compactMap
, so the original "numbers" is unchanged.func multiply (x: Int) -> Int { // Multiply argument by 2 and return. return x * 2 } let numbers = [10, 100, 2000] // Use compactMap on the array. let result = numbers.compactMap(multiply) // Before and after. print(numbers) print(result)[10, 100, 2000] [20, 200, 4000]
As a primary collection in Swift, arrays are versatile and useful. An array has a dynamic size: it grows in capacity to accommodate elements.