Exploring Swift Collections: In-Depth Guide to Arrays, Sets, and Dictionaries

Exploring Swift Collections: In-Depth Guide to Arrays, Sets, and Dictionaries

iOSSwift
Fix bugs faster! Log Collection Made Easy
START NOW!

In Swift, a “collection” refers to a kind of data types that are capable of holding multiple generic values in a single variable. Collections are fundamental to the Swift language and any other language, as they provide the most fundamental way to store and manage sets of data efficiently and effectively.

Swift provides 3 primary types of collections to store your data in a structured way, namely:

In this article we aim to give you an overview of each. Specifically we want to show how they’re declared, illustrate the most common operations of each, provide comparisons between them where applicable and highlight the various performance considerations.

This is going to allow you understand how all Swift collection types work and will help you to write efficient code for data handling in Swift.

Swift Arrays

Arrays in Swift, as in most languages, are representations of lists of items. This is the simplest type of collection, since it merely consists of a group of items put together for convenience.

Declaring Arrays

There’s several ways to declare an Array in Swift. The most common pattern is to simply wrap the type of array you’re declaring in square brackets, or directly wrap the initial values in Square brackets:

let emptyStringArray = [String]()

let stringArray = ["String1", "String2", "String3", "String4"]

We can visualise this as a sequence of elements:

While declaring Arrays with values is pretty much always done the same way, empty arrays can be declared in several different ways. For example:

let emptyStringArray2: [String] = []

let emptyStringArray3 = Array<String>()

Common array operations

The most common operations when using arrays are:

  • Accessing elements
  • Insertion
  • Remotion
  • Sorting
  • Iteration through the Array

Now let’s look at each of them, so we can understand their usage:

Accessing elements of a Swift array

Arrays are lists. So how do we access elements once we’ve created them?

Well there are two ways. We can simply access them by using their index, which starts from 0, or we can access them directly if they’re the first/last elements:

var stringArray = ["1", "2", "3", "4"]

print(stringArray[0]) //This will print "1"
print(stringArray[1]) //This will print "2"
print(stringArray[2]) //This will print "3"
print(stringArray[3]) //This will print "4"
print(stringArray.first) //This will print "1"
print(stringArray.last) //This will print "4"

Bear in mind that trying to access an element that does not exist will create an exception and, if it isn’t appropriately dealt with, your app will crash. Therefore, accessing elements without checking if they exist is discouraged. We will delve into this later on.

Appending elements to a Swift array

We can add elements simply by using the append function, which adds the elements to the tail of the array:

var stringArray = ["1", "2"]
stringArray.append("3")
stringArray.append("4")

print(stringArray) //This will print ["1", "2", "3", "4"]

Visually, this is what happens:

Inserting elements to a Swift array

We can also add elements to specific positions in the array by using insert:

var stringArray = ["1", "2"]
stringArray.insert("3", at: 0)
stringArray.insert("4", at: 3)

print(stringArray) //This will print ["3", "1", "2", "4"]

Note: When inserting, we can insert into either one existing index, or the next index that may be available.

Taking the example above, if we instead tried to insert “4” at position 7, we would create an exception and our app would crash. So just like with insertions, we should be careful here.

Here’s how these operations look visually:

Additionally we can add an entire collection of elements to our arrays:

var stringArray = ["1", "2"]
var stringArray2 = ["3", "4", "5"]

stringArray.append(contentsOf: stringArray2)

print(stringArray) //This will print ["3", "1", "2", "4", "5"]

Removing elements from a Swift array

Removing elements is very similar to inserting them. We can do it by their index, or in some cases by their position:

var stringArray = ["1", "2", "3", "4", "5"]
stringArray.remove(at: 3)
print(stringArray) //This will print ["1", "2", "3", "5"]

stringArray.removeFirst()
print(stringArray) //This will print ["2", "3", "5"]

stringArray.removeLast()
print(stringArray) //This will print ["2", "3"]

The visual representation will look like this:

We can also remove the entire list of elements, clearing the array:

var stringArray = ["1", "2"]
stringArray.removeAll()

print(stringArray) //This will print []

Sorting a Swift array

When it comes to default sorting, there’s two possible ways to do it. We can sort the items within the same array, so won’t have a new variable, but the original array will be modified:

var stringArray = ["2", "1", "5", "4", "3"]
stringArray.sort()
print(stringArray) //This will print ["1", "2", "3", "4" "5"]

Or we can leave the current array as is, and return a version that is sorted:


var stringArray = ["2", "1", "5", "4", "3"]
var stringArray2 = stringArray.sorted()
print(stringArray) //This will print ["2", "1", "5", "4", "3"]
print(stringArray2) //This will print ["1", "2", "3", "4" "5"]

Custom classes offer more advanced ways of sorting, and we explore these in a separate article with more in-depth array operations.

Iterating through the array

When we have an array, we can iterate through it using For loops.

There’s a few ways of doing this: in this case, we’ll show you various For variations that allow us to count the amount of “2” instances in an array.

The For-in examines the element’s index, as follows:

var stringArray = ["2", "1", "2", "4", "2", "7", "8"]
var twosCount = 0

for index in stringArray.indices {
    if stringArray[index] == "2" {
        twosCount += 1
    }
}

print(twosCount)

The For-in that looks at each object itself:

var stringArray = ["2", "1", "2", "4", "2", "7", "8"]
var twosCount = 0

for element in stringArray {
    if element == "2" {
        twosCount += 1
    }
}

print(twosCount)//Prints 3

The For-each also looks at each object:

var stringArray = ["2", "1", "2", "4", "2", "7", "8"]
var twosCount = 0

stringArray.forEach { element in
    if element == "2" {
        twosCount += 1
    }
}

print(twosCount)//Prints

By default, when iterating through objects, we will prefer the For-Each. However, if for any reason we’re focused specifically on the element’s index, we can use the For-in.

Performance of Swift arrays

The performance is O(n), since the time it takes to go through an array is linear and directly linked to the Array’s size.

Swift Sets

Sets have two specific features that distinguish them from an Array:

Ordering – Sets, unlike Arrays, are unordered chunks of data. While an array is easily visualised as a sequence of elements, if we wanted to visualize a set, it would be something like the following:

The elements are randomly present in the set.

Uniqueness: Each element has to be identifiable and unique. This is easily visualised for clarity.

Initialization and insertion of a Swift set

Now let’s see how we declare a set:

var stringSet: Set<String> = ["1", "2", "3"]
print(stringSet) //prints ["1", "2", "3]

This creates the following set:

Now that we have the set, let’s insert an element into it:

stringSet.insert("4")
print(stringSet) //prints [ "4", "2", "1", "3]

Our set now looks like this:

And now lets add another element into it:

stringSet.insert("1")
print(stringSet) //prints [ "4", "1", "2", "3]

This didn’t change our set at all:

As we said before, the sets have unique elements. Therefore, by adding another “1”, the set replaces the existing “1” and we still have four elements.

Common Swift set operations

Operations in sets are way more mathematical than the ones in arrays, and the main ones are as follows:

  • Union.
  • Symmetric difference.
  • Intersection.
  • Subtraction.

All of these are easy to understand when we look at them.

let stringSet1: Set = ["1", "2", "3", "4", "5"]
let stringSet2: Set = ["1", "4", "cat", "duck", "horse"]
let stringSet3: Set = ["1", "4"]

print(stringSet1.union(stringSet2))
// ["1", "2", "3", "4", "5", "cat", "duck", "horse"]

print(stringSet2.symmetricDifference(stringSet3))
// ["cat", "duck", "horse"]

print(stringSet2.intersection(stringSet1))
// ["1", "4"]

print(stringSet2.subtracting(stringSet1))
// ["cat", "duck", "horse"]

Iterating through a Swift set’s elements

Since sets have no direct method of iteration, any operation of that kind needs to be performed in an array.

You can easily turn a set into an array by doing the following:

let stringSet1: Set = ["1", "2", "3", "4", "5"]

let stringAray = stringSet1.sorted()
print(stringArray) //["1", "2", "3", "4", "5"]

By converting a set to an array as shown, all operations available to arrays become available.

Performance of a Swift set

As demonstrated above, we’ll initially need to convert the set to an array in the majority of set access. Thus, just as with arrays, the performance is O(n).

Swift Dictionaries

Dictionaries are the most flexible data structure that we’re going to discuss. They work as repositories of key-value pairs.

We can see the basic declaration of a dictionary, and how it is represented in memory. Let’s now declare a dictionary that includes integer keys and corresponding string values:

let dictionary: [Int: String] = [1 :"one", 2: "two", 3: "three"]

In our app’s memory, this is how it will be represented:

Both the keys and values can be anything, the only limitation for the key is that it is unique. As seen previously, with sets, if we add a duplicate key to a dictionary it will replace the previous key that existed.

So, now that we’ve seen the basics, how do we add/remove elements to a dictionary?

Adding elements to a Swift dictionary

We simply use the key as we used the array’s index, and give it a value:

var dictionary: [Int: String] = [1 :"one", 2: "two", 3: "three"]

dictionary[4] = "four"
dictionary[5] = "five"

print(dictionary)//prints [3: "three", 5: "five", 2: "two", 4: "four", 1: "one"]

You can clearly see another similarity with sets: they do not store order.

Be aware that we are using standard types here, but you can also use your custom objects as long as they implement the Hashable protocol.

Removing elements from a Swift dictionary

Removing elements is very straightforward. We simply need to know which key’s value we want to remove. Then both key and value get removed.

var dictionary: [Int: String] = [1 :"one", 2: "two", 3: "three"]

dictionary.removeValue(forKey: 1)
dictionary.removeValue(forKey: 3)

print(dictionary) //prints [2: "two"]

Accessing elements from a Swift dictionary

As is the case with remotion, we can easily access our values with the named keys associated.

var dictionary: [Int: String] = [1 :"one", 2: "two", 3: "three"]

print(dictionary[1]) //prints [2: "two"]
print(dictionary[0]) //prints [1: "one"]

Here are some other ways of accessing our elements in dictionaries:

It is possible to iterate our dictionaries in a way that is very similar to what we do in arrays, using a For-In.

var dictionary: [Int: String] = [1 :"one", 2: "two", 3: "three"]

for (key, value) in dictionary {
    print(key)
    print(value)
}
//This will print:
// 1
// one
// 2
// two
// 3
// three

Additionally we can iterate with For cycles through our keys, or our values:

var dictionary: [Int: String] = [1 :"one", 2: "two", 3: "three"]

for value in dictionary.values {
    print(value)
}
//This will print:
// one
// two
// three

for key in dictionary.keys {
    print(value)
}
//This will print:
// 1
// 2
// 3

Performance of dictionaries in Swift

Accessing a dictionary directly is as performant as can be, so it takes O(1) time.

On the other hand, accessing elements through cycles relies on making the keys/values into arrays, and therefore the performance is the same as regular arrays, namely O(n).

Swift Collections FAQ

What are the primary collection types in Swift?

Swift offers three main collection types: Arrays, Sets, and Dictionaries, each serving distinct purposes in data storage and manipulation.

How do you declare and initialize an Array in Swift?

Arrays in Swift can be declared using square brackets around the type or directly around initial values. For example: let emptyStringArray = [String]() or let stringArray = ["String1", "String2"].

What is the main difference between Sets and Arrays in Swift?

The key difference is that Sets are unordered and each element must be unique, while Arrays are index ordered collections where duplicate values are allowed.

How do you add and remove elements in a Swift Dictionary?

Elements can be added to a Dictionary by assigning a value to a unique key, and removed using the removeValue(forKey:) method.

Can Swift Arrays contain elements of different types?

By default, Swift Arrays are homogenous. However, you can store multiple types in an array using type casting or by defining the array to store elements of a common superclass or protocol.

How can you handle optionals while accessing Dictionary values in Swift?

When accessing values from a Dictionary, you often deal with optionals. Use optional binding or the nil-coalescing operator to safely handle these cases.

How do you handle errors when accessing array elements by index in Swift?

Accessing an array with an index out of its bounds can cause a runtime error. To handle this safely, you should check that the index is within the array’s count or use methods that return an optional. You can even extend your array to create a safe access method.

To Sum Up

There are three distinct types of Collections natively in Swift. They all have their purpose and should be used appropriately throughout development.

To finish, we will now try to help you understand what to choose and when, based purely on your needs. To identify the most appropriate collection, start by asking yourself a few questions:

  • Do I just need a simple container in which to store values? Array.
  • Do I need to make sure all values are unique? Set.
  • Do I have a straightforward way of mapping each element to a certain key? Dictionary.

It’s really that simple. So happy coding guys!

Expect the Unexpected! Debug Faster with Bugfender
START FOR FREE

Trusted By

/assets/images/svg/customers/highprofile/tesco.svg/assets/images/svg/customers/projects/eye-d.svg/assets/images/svg/customers/highprofile/deloitte.svg/assets/images/svg/customers/projects/slack.svg/assets/images/svg/customers/cool/domestika.svg/assets/images/svg/customers/cool/continental.svg/assets/images/svg/customers/highprofile/intel.svg/assets/images/svg/customers/highprofile/disney.svg

Already Trusted by Thousands

Bugfender is the best remote logger for mobile and web apps.

Get Started for Free, No Credit Card Required