Swift Arrays

by Dimitris Tasios
12 views

In this article, we’ll take a look into one of Swift’s collection types, Swift Arrays. We’ll see how to create an Array, some of its characteristics, and a few main functions, through examples.

If you would like to read about Swift’s other two collection types, you may read about Sets in this article, and Dictionaries in this article.

1. What Are Arrays in Swift?

In Swift, arrays are collection types, which means that they represent a collection of multiple different values of the same type, in the form of a list with indexes. They can contain duplicate values at different positions, even null values if they’re declared as such. They are the shorthand form of the Array class.

You can image arrays as a list of items that have a specific placement in the list. For example, let’s say that we want to list a few Spanish-speaking countries. An array from that list would look like the following diagram:

Figure 1. An array of a few Spanish-speaking countries.

As you can see, every value (country in our case) has a specific placement in the array. Arrays are zero-indexed so we begin counting from 0 instead of 1. For example, “Spain” is at index 0, “Mexico” is at index 1, and so on. So, unless we modify the order of the elements, they will always remain in the same position.

2. How to Create Arrays in Swift?

In order to create an array, we follow a similar syntax to when creating a variable. The difference is that for an array we have to surround its type or values in square brackets ([]).

2.1 Creating an Empty Array

In order to create an empty array of type String, for instance, we would write the following:

var emptyStringArray: [String] = [] // a mutable empty array of Strings
var anotherEmptyStringArray = [String]() // another way to write it, with type inference

print(emptyStringArray.isEmpty)
print(anotherEmptyStringArray.isEmpty)

The output is:

true
true

In the example above, we’ve seen two ways of creating an empty array.

  • The first one (line 1) explicitly declares the array’s type in square brackets and then assigns a value of [] to it.
  • The second one (line 2) uses type inference to “understand” its type, based on the value after the equals sign (=). In this case, we enclose its type in square brackets, followed by parenthesis.

The isEmpty property is available to all Swift arrays and informs us about whether the array is empty or not. As you can see, both of those arrays are empty. The way we declare an empty array comes down to preference.

Note that in the case of creating an empty array, we have to explicitly denote a type for it. If we don’t, then we’ll get a compilation error. For instance, the following initialization is not valid:

var invalidEmptyArray = [] // compile-time error, type of array has not been declared, we need to explicitly declare it

2.2 Creating a Non-empty Array

On the other side, creating a non-empty array is as simple. We write all our values separated by commas and enclosed in square brackets. All values must be of the same type otherwise, it’s a compile-time error.

var nonEmptyArray: [Double] = [2.0, -5.2, 3.3, 10.2]
var invalidArray: [Int] = [3, 5.6, "Six"] // invalid, the array only accepts integers

With this syntax, we don’t need to explicitly indicate the type of the array, as this will be done by Swift through type inference. So, the nonEmptyArray could be written in a simpler way:

var simplerNonEmptyArray = [2.0, -5.2, 3.3, 10.2] // type of array is implied by type inference

The last syntax will automatically make simplerNonEmptyArray a Double array. In case we wanted a Float array, our only option is to use the first syntax that explicitly denotes a type. This is done because Swift automatically denotes decimal numbers as Double and integers as Int. You may read more about Swift’s types in our article here.

There is also a way to initialize a non-empty array with default values automatically. This can be done with Array‘s initializer Array(repeating:, count:). It accepts two parameters; repeating is the initial value that we want to include in the array while count is the number of times we want to repeat that value.

For the following examples, we’ll use the following function that prints the elements of an array, to avoid typing the same few lines over and over.

private func printArray(array: [Any], message: String? = nil) {
    if let message = message {
        print(message)
    }
    
    for element in array {
        print(element)
    }
    
    print()
}
var clhArray = Array(repeating: "Code Learn Hub", count: 5)
var defaultIntegersArray = Array(repeating: 3, count: 3)

printArray(array: clhArray)
printArray(array: defaultIntegersArray)

The output is:

Code Learn Hub
Code Learn Hub
Code Learn Hub
Code Learn Hub
Code Learn Hub

3
3
3

3. Operations and Functions of Swift Arrays

In this section, we’ll see some main operations and a few functions that we can perform on arrays. For the purposes of this article, we won’t see or use higher-order functions, such as forEach or first(where:).

3.1 Accessing an Element of the Array

One of the most useful operations of an array is the ability to access one of its elements. To do so, we use the following syntax:

yourArray[index_of_element]

In this syntax, yourArray is the array whose element we want to access and index_of_element is the index of the element. The index must be within the bounds of the array, so it has to be from 0 up to the number of elements in the array, minus 1 (since arrays start counting from 0). If it’s negative or greater than the number of elements minus 1, then we’ll get a run-time error, which means that our program will crash if it encounters such an index.

var colors = ["Red", "Green", "Blue", "Yellow"]
let firstColor = colors[0]
print(firstColor)

The output is:

Red

And here is an example of invalid indexes:

let invalidColor1 = colors[-1]  // run-time error! negative numbers are always out of range
let invalidColor2 = colors[4]   // any number greater than (number of elements - 1) = 3 is out of range

In this case, we won’t get a compile-time error because both -1 and 4 are integers, so they are valid as far as the type is concerned. However, if the run either of those two lines, our program will crash with the following error:

Swift/ContiguousArrayBuffer.swift:580: Fatal error: Index out of range

As you can see, this type of error is quite sneaky and dangerous, as it cannot be detected before running our program and will crash it when it encounters it. We have to be careful when we try to access the elements of an array. With proper checks (if statements for example) we can be sure that those errors will never occur in our programs.

3.2 Checking the Number of Elements of an Array With the count Property

Arrays in Swift have a convenient property called count, which returns the number of elements of an array.

var colors = ["Red", "Green", "Blue", "Yellow"]
let numberOfElementsInColorsArray = colors.count // 4

Our aforementioned check to prevent run-time errors would be to check that its index is a positive number and less than yourArray.count.

3.3 Checking if an Array Is Empty With the isEmpty Property

Another useful property of arrays is the isEmpty property, which checks whether the array is empty.

var colors = ["Red", "Green", "Blue", "Yellow"]
let isColorsEmpty = colors.isEmpty // false

Our previous check for run-time errors would be improved by first checking that the array is not empty. So, the safest way to access an array whose size might differ between executions would look like this:

if !yourArray.isEmpty && index > 0 && index < yourArray.count {
    // operations with yourArray[index]
}

3.4 Modifying the Value of an Element at a Specific Index

In order to modify the value of an element at an index, we use the syntax of accessing an element and then assigning that with another value of the same type. Modifying the value of elements of an array can only be done when the array is mutable (see section 4 below).

var colors = ["Red", "Green", "Blue", "Yellow"]

printArray(array: colors)
colors[0] = "Magenta" // we modify the value of the first element
printArray(array: colors)

The output is:

Red
Green
Blue
Yellow

Magenta
Green
Blue
Yellow

3.5 Adding an Element to an Array

We have multiple options to add an element to an array, depending on whether we want to add the element at the end or at a specific index of the array. The element that is being added must have the same type as the rest of the elements of the array. The size of an array is dynamic and can be altered as much as we want. Adding elements only be done when the array is mutable (see section 4 below).

3.5.1 Adding an Element at the End of an Array

There are two options for adding an element at the end of an array. The first option is to use the append function, while the other option is to use the += operator. When using the latter option, we must enclose the value in square brackets. Here’s an example of using both of those options:

var fruit = ["Apple", "Banana", "Pear"]
printArray(array: fruit, message: "Fruit array initially:")

fruit.append("Peach")
printArray(array: fruit, message: "Adding \"Peach\" at the end of the array (\"append\" function):")

fruit += ["Pineapple"]
printArray(array: fruit, message: "Adding \"Pineapple\" at the end of the array (\"+=\" operator):")

The output is:

Fruit array initially:
Apple
Banana
Pear

Adding "Peach" at the end of the array ("append" function):
Apple
Banana
Pear
Peach

Adding "Pineapple" at the end of the array ("+=" operator):
Apple
Banana
Pear
Peach
Pineapple

We can also add multiple values at once with the append(contentsOf:) function or the += operator, like so:

var moreFruit = ["Grape", "Strawberry"]

fruit.append(contentsOf: moreFruit)
printArray(array: fruit, message: "Adding two fruit with the \"append(contentsOf)\" function:")

// alternatively
//fruit.append(contentsOf: ["Grape", "Strawberry"])

var evenMoreFruit = ["Cherry", "Mango"]
fruit += evenMoreFruit
printArray(array: fruit, message: "Adding two fruit with the \"+=\" operator:")

// alternatively
//fruit += ["Cherry", "Mango"]

The output is:

Adding two fruit with the "append(contentsOf)" function:
Apple
Banana
Pear
Peach
Pineapple
Grape
Strawberry

Adding two fruit with the "+=" operator:
Apple
Banana
Pear
Peach
Pineapple
Grape
Strawberry
Cherry
Mango

The “alternatively” commented statements indicate that we can use the append(contentsOf:) function and the += operator with literal array values, instead of only variables. We included them to show that it’s possible to use those statements directly.

3.5.2 Adding an Element at a Specific Index of the Array

Alternatively, we can add an element at any valid index of an array, by using the insert(_, at:) function for one element. The elements after the newly-inserted one are shifted by one place. The index must be valid; the array must not be empty and the index must be between 0 and array.count - 1.

var fruit = ["Apple", "Banana", "Pear"]
printArray(array: fruit, message: "Fruit array initially:")

fruit.insert("Kiwi", at: 1)
printArray(array: fruit, message: "Inserting \"Kiwi\" at second place:")

The output is:

Fruit array initially:
Apple
Banana
Pear

Inserting "Kiwi" at second place:
Apple
Kiwi
Banana
Pear

We can, also, add multiple values at one place with the insert(contentsOf:, at:) function. The elements after the newly-inserted ones are shifted by as many places as the newly-inserted elements are.

var moreFruit = ["Grape", "Strawberry"]
fruit.insert(contentsOf: moreFruit, at: 2)
printArray(array: fruit, message: "Inserting two more fruits at third place:")

The output is:

Inserting two more fruits at third place:
Apple
Kiwi
Grape
Strawberry
Banana
Pear

3.6 Removing an Element From an Array

Similarly, we can remove one or more elements from an array. We have multiple options to choose from when wanting to remove elements.

3.6.1 Removing One Element at a Specific Index With remove(at:)

This function removes one element from the specific index. The rest of the elements after that index are shifted by one spot, to cover the newly-emptied spot. This function returns the removed element, which we may choose to ignore if we don’t need it. The index must be valid; the array must not be empty and the index must be between 0 and array.count - 1.

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
printArray(array: vegetables, message: "Vegetables array initially:")

let removedVegetable = vegetables.remove(at: 3) // Garlic is removed
printArray(array: vegetables, message: "Removing \"\(removedVegetable)\":")

The output is:

Vegetables array initially:
Artichoke
Lettuce
Onion
Garlic
Potato

Removing "Garlic":
Artichoke
Lettuce
Onion
Potato

3.6.2 Removing the First or Last Element of an Array With removeFirst() And removeLast()

There is also an option to simply remove the first or the last element of the array. This is done by removeFirst() and removeLast() functions respectively. Both of those functions return the element they removed, which we may choose to ignore if we don’t need it.

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
printArray(array: vegetables, message: "Vegetables array initially:")

let removedFirstVegetable = vegetables.removeFirst()
printArray(array: vegetables, message: "Removing the first vegetable (\(removedFirstVegetable)):")

let removedLastVegetable = vegetables.removeLast()
printArray(array: vegetables, message: "Removing the last vegetable (\(removedLastVegetable)):")

The output is:

Vegetables array initially:
Artichoke
Lettuce
Onion
Garlic
Potato

Removing the first vegetable (Artichoke):
Lettuce
Onion
Garlic
Potato

Removing the last vegetable (Potato):
Lettuce
Onion
Garlic

3.6.3 Removing Multiple Sequential Elements From an Array With removeSubrange()

This function accepts a valid range as a parameter and removes all elements that exist in that range. The range must be valid; its lower bound isn’t negative and its upper bound isn’t greater than array.count - 1. If the range is invalid, then we get a run-time error. You may read more about ranges and their terminology in our article here.

Let’s take a look at a valid example first:

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
printArray(array: vegetables, message: "Vegetables array initially:")

vegetables.removeSubrange(1...3)
printArray(array: vegetables, message: "Removing the second, third, and fourth vegetables:")

The output is:

Vegetables array initially:
Artichoke
Lettuce
Onion
Garlic
Potato

Removing the second, third, and fourth vegetables:
Artichoke
Potato

Now, let’s move on to the invalid examples, starting with an invalid range with a negative lower bound:

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
vegetables.removeSubrange(-1...3) // run-time error

The output is:

Swift/Array.swift:1712: Fatal error: Array replace: subrange start is negative

And, now, the invalid range with an upper bound greater than array.count - 1.

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
vegetables.removeSubrange(1...10) // run-time error

The output is:

Swift/Array.swift:1715: Fatal error: Array replace: subrange extends past the end

3.6.4 Removing the First k or Last k Elements With removeFirst(_ k) And removeLast(_ k)

Those functions remove the first or last k elements from the array. Trying to remove more elements than those the array has, will result in a run-time error.

Let’s see the valid example first:

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
printArray(array: vegetables, message: "Vegetables array initially:")

vegetables.removeFirst(2)
printArray(array: vegetables, message: "Removing first two vegetables:")

vegetables.removeLast(2)
printArray(array: vegetables, message: "Removing last two vegetables:")

The output is:

Vegetables array initially:
Artichoke
Lettuce
Onion
Garlic
Potato

Removing first two vegetables:
Onion
Garlic
Potato

Removing last two vegetables:
Onion

Now, let’s move on to the invalid examples, starting with removing more elements from the beginning of the array than it has:

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
vegetables.removeFirst(10) // run-time error

The output is:

Swift/RangeReplaceableCollection.swift:599: Fatal error: Can't remove more items from a collection than it has

And, now, removing more elements from the end of the array than it has:

var vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"]
vegetables.removeLast(10) // run-time error

The output is:

Swift/RangeReplaceableCollection.swift:885: Fatal error: Can't remove more items from a collection than it contains

3.6.5 Removing All Elements of an Array With removeAll()

This function removes all elements from an array. The resulting array is an empty array of the same type.

vegetables = ["Artichoke", "Lettuce", "Onion", "Garlic", "Potato"] // resetting array
printArray(array: vegetables, message: "Vegetables array initially:")

vegetables.removeAll()
printArray(array: vegetables, message: "Removing all vegetables")
print(vegetables.isEmpty)

The output is:

Vegetables array initially:
Artichoke
Lettuce
Onion
Garlic
Potato

Removing all vegetables

true

4. Mutability of Swift Arrays

As you might have noticed, in all of our examples we have declared arrays as variables with the var keyword. This makes those arrays mutable. In a mutable array, we can:

  1. Change the values of its elements.
  2. Add more elements.
  3. Remove elements from it.

If we create an array as a constant with the let keyword, then the array becomes immutable. In an immutable array, we cannot perform the aforementioned three operations, because such an array doesn’t allow changes. If we try to perform those operations, we’ll get a compile-time error.

let clhWebsite = ["Code", "Learn", "Hub"]
clhWebsite[0] = "Swift"     // compile-time error, Cannot assign through subscript: 'clhWebsite' is a 'let' constant
clhWebsite.append(".com")   // compile-time error, Cannot use mutating member on immutable value: 'clhWebsite' is a 'let' constant
clhWebsite.removeFirst()    // compile-time error, Cannot use mutating member on immutable value: 'clhWebsite' is a 'let' constant

You may read more about variables and constants in Swift in our article here.

5. Iterating Through Swift Arrays With for Loops

We can use for loops with arrays in order to access all of their elements one by one. We have already used a for loop for our printArray function in our examples above.

In the following example, we simply iterate through the elements of the array, without needing the element’s index in each iteration:

let clhAuthors = ["Dimitris", "Akis", "John/Ignis"]

for clhAuthor in clhAuthors {
    print("Presenting CLH's author: \(clhAuthor)")
}

The output is:

Presenting CLH's author: Dimitris
Presenting CLH's author: Akis
Presenting CLH's author: John/Ignis

If we wanted to know the index of the element on every iteration, we would have to use the enumarated() function and alter the for loop as such:

let clhAuthors = ["Dimitris", "Akis", "John/Ignis"]

for (index, clhAuthor) in clhAuthors.enumerated() {
    print("Presenting CLH author number \(index + 1): \(clhAuthor)")
}

The output is:

Presenting CLH author number 1: Dimitris
Presenting CLH author number 2: Akis
Presenting CLH author number 3: John/Ignis

6. Conclusion

By now, you should have a clear understanding of how to create and use arrays in Swift. You can find the source code (Playground) on our GitHub page.

Related Posts