DEV Community

Cover image for Exploring Swift Collections: In-Depth Guide to Arrays, Sets, and Dictionaries
Bugfender
Bugfender

Posted on • Originally published at bugfender.com on

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

In Swift there are 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"]

Enter fullscreen mode Exit fullscreen mode

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>()

Enter fullscreen mode Exit fullscreen mode

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"

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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 []

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

Custom classes offer more advanced ways of sorting, and we will 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)

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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.

Explore Swift Closures in-depth in our detailed guide, covering their syntax and practical uses.


Swift Closures Explained: A Comprehensive Guide for iOS Developers

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]

Enter fullscreen mode Exit fullscreen mode

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]

Enter fullscreen mode Exit fullscreen mode

Our set now looks like this:

And now lets add another element into it:

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

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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).

Discover the intricacies of date and time handling in Swift with our article. It provides practical strategies for effectively working with dates, crucial for time-sensitive Swift applications.


Mastering Swift Date Operations: A Comprehensive Guide for iOS Developers

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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

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"]

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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.

Even as an iOS developer, exploring Android’s capabilities can be helpful. Gain insights into Kotlin Collections and learn how to use it for your Android app development.


Leveraging Kotlin Collections in Android Development

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!

Top comments (0)