The need to work with collections of values is pretty common in Swift. To help with this, Swift provides a number of collection types, flexible containers that let you store a number of different values together within a single entity. One of the most common of these is the Array, and in this article, we’re going to go over the basics. Let’s dive in.
Table of Contents
What is an Array?
Arrays are the most common type of collection you’ll run into in Swift and store an ordered collection of values within a single aggregated type.
Here is an example. Say we wanted to hold a list of items for a shopping list. One option would be to store them as an array:
As you can see we have five elements in our example array, located at indexes 0 through 4.
In Swift, like in many languages, arrays are zero-indexed meaning the first element in the array is referred to with an index of 0, the second one with an index of 1 and so on. The last element in the array always has an index that is equal to the number of elements in the array minus one.
It’s also worth pointing out that arrays in Swift are strongly typed.
Each of the elements in this example would be of type String
, but arrays can be used to hold values of any type you like, just as long as all the values in the array are of the same type. Being strongly typed, the Swift compiler will enforce this fact and will raise an error if you try to add a value of the wrong type.
You’ll also notice another thing about arrays. They can include the same value multiple times in different positions as I’ve done here with our Apples
. This can be extremely useful in certain situations and is what differentiates Arrays from some of the other collection types available in Swift.
Array Mutability
Just like with other variables and constants, the mutability of an array is controlled by whether the array is declared to be a constant or variable.
If it is stored in a variable, the collection is said to be mutable meaning it can be changed. Elements can therefore be added and deleted and also altered.
If it is stored in a constant, the collection is said to be immutable meaning both its size and contents cannot be changed . As with other variables and constants in Swift, it is best practice to define an array to be a constant unless you have a good reason not to.
Declaring and Initialising Arrays
There are a number of different ways to declare and initialise an array in Swift.
Declaring Array Constants and Variables
The first way is to declare it using Swifts type annotation syntax.
Here we use the normal let
or var
keyword to declare either a constant or a variable, the name of the variable or constant we want to declare and then a type annotation to indicate the types of values that will be stored in the Array.
For arrays, the type annotation is written using the Array
keyword followed by the type of items that will be held in the array between a pair of angled brackets. This style of declaration is an example of Swifts generics syntax, something we will likely look at in a future post:
let myFirstArray : Array<Int>
In this example I’ve declared a new constant array that will hold values of type Int
. As I’ve mentioned, Arrays in Swift are strongly typed and now that we have declared it, the Swift compiler will enforce the fact that this array can contain only values of type Int
and will raise an error if we try to add values of the incorrect type.
Inferred Array Declaration
The second way to declare array constant and variables in Swift is to take advantage of Swift’s type inference mechanism.
In this approach, we don’t provide a type annotation for the variable or constant but instead let Swift infer the arrays type from from the initialiser we use:
let firstEmptyArray = Array<Int>()
Here we again use the Array
keyword followed by the type of values that will be held in the array between a pair of angled brackets. This time though, we use this to the right of the assignment operator and combine it with an empty pair of parentheses.
The parentheses in this example represent a call to the default initialiser method for the Array
type and creates an empty array instance that holds values of the specified type. Swift then uses this instance to infer the type of the daysPerMonth
constant.
We’re not done there though.
We also have the option of writing this declaration and initialisation a slightly shorter form as well.
Instead of using the full Array
syntax we’ve just seen, we can also write the type of values to be held in the array between a pair of square brackets instead. This is again followed by a pair of empty parentheses to call the default initialiser:
let anotherEmptyArray = [Int]()
Both of these examples are semantically identical and in both cases, they create an empty array that hold values of the specified type. If you’re following along in a Playground, you’ll see in both cases that Swift represents these empty arrays using a pair of empty square brackets ([]
).
Whilst you’re in the Playground, it’s also interesting to look at the types of these two values.
If you look at our first example (the firstEmptyArray
constant), you’ll see that Swift infers it to be of type Array
. In the latter example, (the anotherEmptyArray
constant), the constant is inferred to be of type [Int]
. Although on the face of it these type types appear different, in reality they are functionally identical in Swift and can be used interchangeably.
So, we’ve seen how to declare array variables and constants and we’ve seen how to initialise them with an empty array using the default initialisers, but on their own, these aren’t particularly useful. What we need is a way to declare arrays that contain an initial set of values. There are a number of ways to do this in Swift, the first of which are called array literals.
Initialising Arrays Using Array Literals
An array literal is a short, concise way to initialise an array with a predefined list of values. The list of values is surrounded by a pair of square brackets and each value is separated from the next by a comma. We’ve already seen an example of an array literal in the playground just now:
let thirdEmptyArray : [Int] = []
This is an example of initialising an array with an empty array literal but as I said, it’s more interesting to declare an array that contains actual values. The following is an example of doing just that:
let daysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Here we again use Swifts type inference mechanism to infer that the ‘daysPerMonth’ constant is of type Array
and initialise the array with the number of days in each month of the year.
Initialising An Array With Default Values
In addition to this array literal syntax, we also have another array initialiser at our disposal that we can use to initialise an array:
let zeroedArray = [Int](count: 7, repeatedValue: 0)
// [0, 0, 0, 0, 0, 0, 0]
As you can see, this time instead of a pair of empty parentheses as we did earlier, this time we call a slightly different initialiser.
In this case, the initialiser takes the number of values we want the array to contain (the count
) along with a default value that will be assigned to each of the arrays elements (the repeatedValue
).
Creating an Array By Adding Two Arrays Together
Another way to create an array is by adding two existing arrays together to create a third, new array.
The two arrays must contain compatible types, but if they do, we can add them together using the addition operator (+
):
let arrayOne = [1, 2, 3]
let arrayTwo = [4, 5, 6]
let arrayThree = arrayOne + arrayTwo
// [1, 2, 3, 4, 5, 6]
Again, if we check the type of the arrayThree
constant in a Playground, we can see that it is inferred to be of the same type as the two original arrays ([Int]
in this case).
Checking the Number of Elements in an Array
Now that we know how to create arrays that contain some values, let’s next look at how we check the contents of an array.
Let’s return to our shopping list example from earlier, but this time in code:
var shoppingList = ["Bread", "Milk", "Cheese", "Apple", "Apple"]
Note: In this case, I’ve defined the shoppingList
array to be a mutable array rather than an immutable one. I’ve done this because we’re going to be adding and modifying elements in the array later in this article.
We can check whether the array is empty by using the read only isEmpty
property of the array. This returns a boolean value indicating whether the array is empty or not:
print(shoppingList.isEmpty)
// false
In our case, the array contains at least one element so isEmpty
returns false
.
We can also retrieve the exact number of elements in the array using the arrays count
property:
print("Your shopping list contains \(shoppingList.count) items.")
// Your shopping list contains 5 items.
Accessing Elements of an Array
To actually access the actual elements in an array, we have a number of options.
Accessing Elements Using Array Properties and Methods
Firstly, Swift provides a couple of different properties that allow us to access different elements in the array directly.
The first of these is the first
property. This allows us to access the first element in the array and as you’ll notice, returns an optional to account for the fact that if the array were empty there would be no element to return:
print(shoppingList.first)
// Optional("Bread")
In addition to the first
property, arrays also have a corresponding last
property that we can use to get the last element in an array. Again, this property returns an optional:
print(shoppingList.last)
// Optional("Apple")
In addition to the first
and last
properties, the Swift array also provides a couple of convenience methods; minElement()
and maxElement()
. These return the minimum and maximum elements from the array respectively.
For arrays containing numeric values, these methods return the minimum and maximum numeric values. In the case of arrays that contain String
values though, they return the elements that are either earliest (for minElement()
) or latest (for maxElement()
) in the alphabet.
Again, both the minElement()
and maxElement()
methods return optional values to account for the fact that the array may contain no elements:
print(shoppingList.minElement())
// Optional("Apple")
print(shoppingList.maxElement())
// Optional("Milk")
So as you can see, there are a bunch of convenience methods to get the first and last elements in an array, but what about accessing elements that are in the middle of an array? This is where array subscripting comes in.
Accessing Array Elements Using Subscripting
As an alternative to the properties or convenience methods that arrays provide, we can also access values within an array using subscripting.
With subscript syntax we use the index of the value that we wish to access within a pair of square brackets immediately after the name of the array.
For example, if we wanted to access the Cheese
element of our shoppingList
array (the third element) we would use the index of that element (2
– remembering that indexes are zero-indexed so the first element is 0, the second element is 1 and the third element is 2):
print("The third item on the list is \(shoppingList[2])")
// The third item in the list is cheese
You have to be careful with this though. If you try to access an element using an index that is beyond the size of the array, you’ll get a runtime error:
print(shoppingList[shoppingList.count])
// Causes a runtime error...
In addition to being able to use a single index within the square brackets we can also use a range. This allows us to retrieve multiple values from an array with a single line of code and returns a new array of the same type as the original that contains a copy of the values from the original array.
Both the open and closed range operators work in this context:
print(shoppingList[0...1])
// "["Bread", "Milk"]"
print(shoppingList[0..<2])
// "["Bread", "Milk"]"
Checking For Elements in an Array
The last thing we’re going to look at when it comes to accessing elements in an array is checking whether an element actually exists within an array.
We can do this using the contains(_:)
method. This method returns a boolean value indicating whether the value exists:
print(shoppingList.contains("cheese"))
// true
Modifying Arrays
When it comes to modifying arrays, we have a whole range of things that we can do including adding elements, modifying elements, removing elements and reordering elements. In this section, we’re going to look at each of these different activities. We’ll start by looking at how to add new elements to an existing array.
Adding Elements to an Array
Imagine the scenario. We have our shopping list, but want to add a new ingredient to it, “Pasta” for example. How can we add this to the list?
The primary mechanism in Swift is to use the append(_:)
method.
This method is another of the methods available on Arrays and can be used to add new values to the end of an existing array.
There are a couple of caveats with its use though. Firstly, the append(_:)
method can only be used with mutable arrays. This means you can only use it with those arrays that you have defined using the var
keyword.
Secondly it can only be used to add elements that are compatible with the array. In our case, this means we can only use it to add new String
elements to the shoppingList
array. Again, if you try to use it to add an incompatible element you’ll get a compiler error:
shoppingList.append("Pasta")
// ["Bread", "Milk", "Cheese", "Apple", "Apple", "Pasta"]
shoppingList.append(2)
// Will cause a compiler error...
As an alternative to the append(_:)
method, we can also add new element to an Array using the addition assignment operator (+=
).
The addition assignment operator is used to append other (compatible) arrays to an existing array. The arrays that are being appended can contain either no elements, a single element or multiple elements, it doesn’t matter as long as they are of the same type. In this example we use it to add two new ingredients to our shopping list:
shoppingList += ["Tomatoes", "Garlic"]
// ["Bread", "Milk", "Cheese", "Apple", "Apple", "Pasta", "Tomatoes", "Garlic"]
Inserting Elements into an Array
As well as appending elements to the end of an array, we can also insert elements into the middle of an array. We can do this using the insert(_:atIndex:)
method:
shoppingList.insert("Oregano", atIndex:3)
// ["Bread", "Milk", "Cheese", "Oregano", "Apple", "Apple", "Pasta", "Tomatoes", "Garlic"]
As you can see, this method takes two parameters, the element we want to insert ("Oregano"
) and the index at which we want to add it (3
).
Again, the element we add needs to be of a compatible type and as you can see from the results, once added all subsequence elements in the array are shifted one index to the right to make room.
In a slight quirk, we can also use the insert(_:atIndex:)
method to append an element to the end of the array.
To do this we use an index parameter one larger than the largest index in the current array. Due to arrays being zero-indexed, this is the same as using an index equivalent to the number of items in the array:
shoppingList.insert("Olive Oil", atIndex: shoppingList.count)
// ["Bread", "Milk", "Cheese", "Oregano", "Apple", "Apple", "Pasta", "Tomatoes", "Garlic", "Olive Oil"]
It works but be careful not to use an index larger than this or you will trigger a runtime error.
Removing Elements from an Array
As you can see, our shopping list is getting quite long now so let’s have a look at how we can remove some items from it. Swift provides a few ways of doing this.
Removing the First or Last Elements of an Array
In similar fashion to the array methods we saw earlier, Swift provides a couple of convenient methods that allow us to remove the first item (using removeFirst()
) and the last item (using removeLast()
) of an array:
let first = shoppingList.removeFirst()
print("You removed the first item: \(first)")
// "You removed the first item: Bread"
let last = shoppingList.removeLast()
print("You removed the last item: \(last)")
// "You removed the last item: Olive Oil"
print(shoppingList)
// ["Milk", "Cheese", "Oregano", "Apple", "Apple", "Pasta", "Tomatoes", "Garlic"]
As you can see, in both these cases, the methods return the item that was removed. This can be extremely useful if you want to do something with the removed item such as printing it out or performing some calculation.
Note: It is worth pointing out at this point that when an element is removed from an array, the space that the element used to occupy is automatically closed by Swift. You can see this above. This means that the index of any subsequent elements in the array is reduced by one as the gap is closed.
Removing an Element By Index
In addition to the removeFirst()
and removeLast()
convenience methods, we can also remove an item at a particular index.
Say we wanted to remove the first of the "Apple"
entries. First we could find out the index of that element in the array by using the indexOf(_:)
method on the array. The indexOf(_:)
method returns an optional which contains either the index of the first element that matches the supplied parameter or returns nil
if the value is not present anywhere in the array:
let appleIndex = shoppingList.indexOf("Apple")
As the indexOf(_:)
method returns an optional we need to unwrap it before we can use it, but once unwrapped we can then use the index with the removeAtIndex(_:)
method to remove the element from the array.
In the example below I’ve used optional unwrapping to unwrap the appleIndex
optional and then called the removeAtIndex(_:)
with the unwrapped value:
if let index = appleIndex {
let removedItem = shoppingList.removeAtIndex(index)
print("You removed the \(removedItem)")
}
// prints "You removed the Apple"
print(shoppingList)
// ["Milk", "Cheese", "Oregano", "Apple", "Pasta", "Tomatoes", "Garlic"]
As you can see, the first Apple
element is removed from the array and is returned by the removeAtIndex(_:)
method.
Updating Elements in an Array
So we now know how to insert and remove elements from an array but what about updating an element? Given everything we know about so far, how would we do it?
Well the obvious answer would be to remove the element we want to modify and then insert a new element and although that would work, there is a better approach in Swift, an approach that sees us revisiting the now somewhat familiar subscript syntax we saw earlier.
Updating a Single Array Element Using Subscripting
In addition to using subscript syntax to access an element as we saw earlier, Swift also allows us to use subscript syntax to modify an element as well. Using subscript syntax is much simpler than inserting and removing different elements but does come with the same warnings about making sure that we use an index that is not beyond the bounds of the array. With that said though, it is the preferred way of modifying elements in an array in Swift. So the question remains how do we do it?
Well, instead of the subscript syntax being used to the right-hand side of an assignment operator as we saw earlier, this time we use the subscript syntax to the left of the assignment operator.
In this case, the index we provide within the pair of square brackets identifies the element of the array we want to modify. We then follow that with an assignment operator (=
) and the new value we want to assign to that element. Lets look at an example.
Say we looked over our shopping list and instead of wanting some sort of generic Cheese
we actually wanted Parmesan Cheese
. To update the Cheese
element of the shopppingList
array we would use name of the array, followed by the index of the element we wanted to modify (within a pair of square brackets) and then use the assignment operator to assign it a new value:
shoppingList[1] = "Parmesan Cheese"
print(shoppingList)
// ["Milk", "Parmesan Cheese", "Oregano", "Apple", "Pasta", "Tomatoes", "Garlic"]
As you can see, the Cheese
element has been updated to Parmesan Cheese
. Where not done with updating our arrays with subscripting though….
Updating Multiple Array Elements Using Subscripting
As we saw when retrieving values from an array, in Swift we also have the option of using a range of values within the subscripting square brackets and we can also use this syntax when we’re updating values.
When used in this way, supplying the array name followed by a range of indexes within a pair of square brackets allows us to update multiple elements within the array using a single line of code. A slight curve ball here though is that the number of elements identified by the range doesn’t actually need to match the number of values we’re updating though. Take this example:
shoppingList[3...4] = ["Penne", "Salt", "Pepper"]
This example update two elements (the "Apple"
and "Pasta"
elements )in our array with three new elements ("Penne"
, "Salt"
, and "Pepper"
) and as you can see, the overall size of the array has actually grown by one element:
print(shoppingList)
// ["Milk", "Parmesan Cheese", "Oregano", "Penne", "Salt", "Pepper", "Tomatoes", "Garlic"]
This might be a little confusing at first but do you remember the question I asked you at the start of this section? The one where I asked you how you might update an element in an array? Remember how one option was to remove the elements and then insert new ones? This is essentially how this range updating approach works: remove the elements we’re updating and then insert the new ones. Simple really. Anyway, lets get away from the mind bending bits and look at how to reorder the elements of an array.
Reordering Array Elements
So, we can now update the elements in an array but one other thing you may want to do with elements is to reorder them.
Remember, arrays hold an ordered list of elements so being able to modify this order can be extremely useful and is unique within Swifts collection types.
In Swift, there are two main ways of reordering Array elements; reordering by removing and re-inserting and reordering by sorting. We’ll look at both of these next.
Reordering Array Elements By Removing and Inserting
By now, you should be pretty used to the idea of removing elements from an array and re-inserting them. We saw it in the last section when we looked at how to update elements in an array. Another use for this technique though is to re-order elements. The idea is pretty simple. Remove the element we want to re-order and then re-insert it at the correct location within the array.
For example, say I wanted to move the "Garlic"
element to be the first item in my shopping list (I’ve no idea why I would want to but go with it for now). One approach to that would be:
let garlic = shoppingList.removeLast()
shoppingList.insert(garlic, atIndex:0)
// ["Garlic", "Milk", "Parmesan Cheese", "Oregano", "Penne", "Salt", "Pepper", "Tomatoes"]
Alternatively, we could use the removeAtIndex(_:)
method to move the "Milk"
element to be the last element in our list:
let milk = shoppingList.removeAtIndex(1)
shoppingList.insert(milk, atIndex:shoppingList.count)
Although this remove / insert technique works well for single items, it can be a little tedious if we want to sort the entire array though. For these much larger reordering operations we have a better alternative; the sort(_:)
method.
Reordering Array Elements by Sorting
In Swift, the Arrays sort()
method does exactly what you’d expect it to. It sorts the elements of the array and returns a new array of the same type and size as the original but with the elements now sorted:
let sortedShoppingList = shoppingList.sort()
print(shoppingList)
// ["Garlic", "Parmesan Cheese", "Oregano", "Penne", "Salt", "Pepper", "Tomatoes", "Milk"]
print(sortedShoppingList)
// ["Garlic", "Milk", "Oregano", "Parmesan Cheese", "Penne", "Pepper", "Salt", "Tomatoes"]
As you can see, the original array is not modified and instead a copy of the original array is returned.
If we wanted to modify the original array, we use another different method, the sortInPlace()
method.
With this method the original array is, as the name suggests, sorted in place and no copy is made:
shoppingList.sortInPlace()
print(shoppingList)
// ["Garlic", "Milk", "Oregano", "Parmesan Cheese", "Penne", "Pepper", "Salt", "Tomatoes"]
In both of these examples the sort()
and sortInPlace()
methods internally use the less than operator (<
) to decide how to sort the elements of the array. In the case of String
values this means sorting alphabetically with values closer to the start of the alphabet towards the start of the array. For numeric values, they are sorted lowest to highest.
One thing to note here is that in this article, I’m only going to scratch the surface of sorting in Swift. For advanced sorting operations there are two alternative methods, the sort(_:)
and sortInPlace(_:)
methods. Although these have the same name, they are in fact different methods and in this case take a single closure parameter. The closure parameter accepts two arguments of the same type as the values being stored in the array and returns a boolean to indicate whether the first value should be before or after the second value when sorting is complete.
By supplying your own closure to these methods you can implement some seriously advanced sorting algorithms including reverse sorting (though also look at the reverse()
method if your specifically interested in this) or even your own bespoke sorting order should you so with. Currently, this is beyond the scope of this article though so for now, we’re going to wrap up by looking at how we can iterate over the contents of an array.
Iterating Over Elements in an Array
Let’s continue our shopping list example and imagine that we were just about to head out to the shops and wanted to print out our shopping list. The main mechanism for achieving this in Swift is the for-in
loop:
for item in shoppingList {
print(item)
}
// Garlic
// Milk
// Oregano
// etc.
As you can see, the for-in
loop works its way through the array from index 0
up to and including the last element of the array (shoppingList.count - 1
). Each time around the loop, the item
variable is set to the item at the current index which is then made available within the body of the for-in
loop which we then print out.
As an extension to this model, we can also beef this up a little by printing out the item indexes as well. If you also wanted to access the index of the item as well as the item itself, we can do so using the enumerate()
method.
The enumerate()
method is one stage beyond the simple for-in
loop and returns a tuple containing the index value and the item:
for (index, item) in shoppingList.enumerate() {
print("Item \(index + 1): \(item)")
}
// Item 1: Garlic
// Item 2: Milk
// Item 3: Oregano
// etc.
Wrap Up
So there we have it. The basics of Swift Arrays and a nice shopping list for a pasta recipe along with it! I hope it has help you get up the Swift learning curve.
As ever, if you have any questions please don’t hesitate to leave them in the comments below.