DEV Community

Cover image for Swift 101: Collections Part I - Arrays
Silvia España Gil
Silvia España Gil

Posted on

Swift 101: Collections Part I - Arrays

Hola Mundo!

Welcome to a new article in a series of Swift 101 notes 📝 I did while learning the language and I decided to share them because why not?.

If you're new to Swift or interested in learning more about this language, I invite you to follow my series! 🙊

In this chapter, I'll share Part I of Collections and Collection Types, where we'll dive into Arrays.


A couple of weeks ago, we discussed constants and variables, which store values for us to use in our code and some simple types. However, there are some other complex types that we will find across our apps📱​.

As you may already guess, "Collections" are types that store many values. They arrange all those values in certain ways so we can access them in the future.

Think of it like a fruit basket with many fruits in it. Similarly, arrays in Swift store multiple values of the same type in an ordered list, like a line of apples, oranges, and bananas neatly arranged in your basket 🍎​🍊​🍌​


Arrays


Arrays are an ordered collection of values and are the most common collection type. Inside an array, we may store any kind of elements of the same type.

Arrays are one of the most commonly used collection types in Swift due to their simplicity and efficiency. Arrays maintain an ordered list of elements. This makes them ideal for scenarios where the order of elements matters, such as lists of items or sequences of tasks.

To create an array, we separate elements with commas and enclose them in square brackets.

let intArray = [1, 2, 3]
let stringArray = ["Mónica", "Rachel", "Phoebe"]
Enter fullscreen mode Exit fullscreen mode

Typing our arrays

As with everything in Swift, arrays are also typed. If we don’t indicate it explicitly, Swift will infer the type for us.

However, for Swift to be able to infer the type, the values inside the array must be homogeneous, meaning all values must be of the same type. This is called array literals.

If we don't type our array, and the values are heterogeneous, we will get an error ❌​, and Swift will ask us to add an explicit type to ensure the mixed types are intentional.

To set a type to an array we must indicate it after the naming just as we do in simple variables and constants.

If we want to create a heterogenous array or we don’t know which kind of values we will hold in that variable we can set the Any type -not recommendable-

Strong typing in Swift ensures that each array can only contain elements of a specific type.

This could prevent many common programming errors and make your code more predictable and easier to debug. By specifying the type of elements Swift can also optimize performance and provide better compile-time checks.

// All values are the same type
let homogenousArray: [Double] = [1.4, 2.6, 3.7]
let alsoHomogenousArray: [String] = ["Pippin", "Merry", "Frodo", "Sam"]
Enter fullscreen mode Exit fullscreen mode

// Values types may be different so type is Any
let heterogenousArray: [Any] = [8, "Kobe Bryant", 24.8]
Enter fullscreen mode Exit fullscreen mode

Classes and structs as types

Until now we have been using the most common types to type all of our values. However, while dealing with our apps, especially if they interact with APIs or complex data, we may need to manage arrays with heterogeneous types.

If you scroll back, I said that we can use Any as a type, but I also said that is not a really good idea🙅🏽‍♀️​. But if Swift gives us that option, why is it not a good idea?

Typing makes our code more reliable, and safer🛟​. We know always what kind of value we are going to find in that variable. With Any we lose that advantage. We may also cause compilation issues, overcomplicate our code, etc.

But we can overcome this by using classes or structs as types.

Let’s imagine that we have a newsletter and we need an array with the user name, email, and confirmation that it wants to receive an email. And we are going to store that in an Array. So first we could create a struct and then assign it as a type.

struct User: Identifiable, Hashable {
    let id: Int
    let name: String
    let email: String
    let permission: Bool
}
var registeredUsers: [User]
Enter fullscreen mode Exit fullscreen mode

In Swift, structs and classes are both used to create complex data types, but they have some key differences. Structs are value types, which means they are copied when assigned to a new variable or constant, or when passed to a function.

Classes, on the other hand, are reference types, so they are passed by reference and can have inheritance.

Generally, is a better idea to use structs for simpler data types that do not require inheritance and classes for more complex types that benefit from inheritance.

✨​Further details on classes and structs will come later on in the series, so don't forget to follow me and keep an eye on new updates.✨​


Array managing: accessing values and methods

Accessing array values

We now know that an array, as a collection, can store one or many values, but to use them we will probably need them separated and to do so we need to access those values.

Using the value index

One way of accessing our array values is by calling the index. As arrays are ordered collections if nothing explicitly changes, the value in a certain position will always be the same.

let hatchNumbers = [4, 8, 15, 16, 23, 42]
let thirdHatchNumber = hatchNumbers[2]
print(thirdHatchNumber) // 15
Enter fullscreen mode Exit fullscreen mode

🧐 Remember that the array index starts at 0. So the first value is index 0 and so on. 🧐

Iterations or loops: For-in and while

There are two ways to iterate an array. One you may use while using SwiftUI in the views and the other one the rest of the time, but don't worry, they are pretty similar.

If you want to know more about this, keep an eye on this series because I'll be writing about Control Flow however, in the meanwhile, we will hammer the most common here: For-in loops

Loops can be imagined as a spiral, each loop of the spiral is an item. So, when we iterate an array, we circle the array over and over.

Imagine we have an array with the Fellowship of the Rings names and I want to access the name of each one of them. We could check the array using a for in loop and print the values.


let fellowshipMembers = ["Frodo", "Sam", "Gandalf", "Aragorn", "Legolas", "Gimli", "Boromir", "Merry", "Pippin"]

// Access elements
for member in fellowshipMembers {
  print(member)
}
Enter fullscreen mode Exit fullscreen mode

What is going to happen is that Swift is going to check each member inside the fellowshipMembers array and will print the nine values.

Frodo
Sam
Gandalf
Aragorn
Legolas
Gimli
Boromir
Merry
Pippin
Enter fullscreen mode Exit fullscreen mode

We can also do the iteration but add a clause in it. For doing so we will have to add a where in the loops.

// Leave Frodo out
let fellowshipMembers = ["Frodo", "Sam", "Gandalf", "Aragorn", "Legolas", "Gimli", "Boromir", "Merry", "Pippin"]
for member in fellowshipMembers where member != "Frodo" {
  print(member)
}
Enter fullscreen mode Exit fullscreen mode

This will print all the Fellowship members but will skip Frodo.

There’s another way to do a loop by evaluating a condition, and that is using while. Basically, we ask Swift that while a condition happens, do something.

Think of it as when you are cooking, while you see flour, whisk the mix. Then you understand that if the flour is not visible anymore you can stop whisking.

while condition {
  do this
}
Enter fullscreen mode Exit fullscreen mode

Let’s imagine that we want to allow Frodo to gather 3 things

var itemsToCollect = ["Ring", "Lembas Bread", "Elven Cloak", "Light of Eärendil", "Mithril Coat"]
var thingsCollected = 0

while thingsCollected < 3 {
    print("Frodo has collected: \(itemsToCollect[thingsCollected])")
    thingsCollected += 1
}
Enter fullscreen mode Exit fullscreen mode

This will print us this

Frodo has collected: Ring
Frodo has collected: Lembas Bread
Frodo has collected: Elven Cloak
Enter fullscreen mode Exit fullscreen mode

While we are looping an array we may want to access to the index value of the element and call the enumerated() method with the array. For doing so we may call the index in the loop.

// Print with index
let fellowshipMembers = ["Frodo", "Sam", "Gandalf", "Aragorn", "Legolas", "Gimli", "Boromir", "Merry", "Pippin"]
for (index, member) in fellowshipMembers.enumerated() {
  print("Member number \(index + 1): \(member)")
}
Enter fullscreen mode Exit fullscreen mode

This will print

Member number 1: Frodo
Member number 2: Sam
Member number 3: Gandalf
Member number 4: Aragorn
Member number 5: Legolas
Member number 6: Gimli
Member number 7: Boromir
Member number 8: Merry
Member number 9: Pippin
Enter fullscreen mode Exit fullscreen mode

🧐 Remember that the array index starts at 0. So the first value is index 0 and so on. 🧐


Array methods and properties

We already know how fundamental are Arrays, they allow us to store multiple values in a single variable, making it easier to manage collections of data.

But to truly harness the 💪​power of arrays💪​, it's essential to understand the various methods and properties that Swift provides for working with them. And that also makes it so much easier to work with them.

What are Array Methods and Properties?

Properties are characteristics of an array that provide information about the array itself. For instance, properties can tell you the number of elements in an array or whether the array is empty.

Methods are functions that perform actions on the array. They can help you add, remove, or find elements within the array, and perform other useful operations.

By learning these methods and properties, you can effectively manipulate arrays and make your code more efficient and readable.

Let's see the most used:

.count

This property counts how many elements are inside an array.

var numbers = [1, 2, 3, 4]
print(numbers.count) 
// Output: 4
Enter fullscreen mode Exit fullscreen mode

.append()

This method allows us to add new elements to the end of the array.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.append("Bread")
print(groceryList) 
// Output: ["Onions", "Apples", "Pasta", "Bread"]
Enter fullscreen mode Exit fullscreen mode

.insert()

This method allows us to add new values to the array at a specific index.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.insert("Bread", at: 1)
print(groceryList) 
// Output: ["Onions", "Bread", "Apples", "Pasta"]
Enter fullscreen mode Exit fullscreen mode

.remove(at:)

This method removes the element at a specific index in the array.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.remove(at: 0)
print(groceryList) 
// Output: ["Apples", "Pasta"]
Enter fullscreen mode Exit fullscreen mode

.removeAll()

This method empties the array of all its values.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.removeAll()
print(groceryList) 
// Output: []
Enter fullscreen mode Exit fullscreen mode

.filter()

This method, filters our array. It creates a new array with the values that satisfy a condition.
For example, let's filter our array to create a new one with all the values that are less than 3.

var numbers = [1, 2, 3, 4]
let filtered = numbers.filter { $0 < 3 }
print(filtered) 
// Output: [1, 2]
Enter fullscreen mode Exit fullscreen mode

.map()

This method transforms each value of the array and returns a new array with the transformed values.

var numbers = [1, 2, 3, 4]
let mappedNumbers = numbers.map { $0 * 2 }
print(mappedNumbers) 
// Output: [2, 4, 6, 8]
Enter fullscreen mode Exit fullscreen mode

.forEach()

This method performs an action for each value in the array.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.forEach { print($0) }
/* Output: 
   Onions
   Apples
   Pasta
*/
Enter fullscreen mode Exit fullscreen mode

.sort(by:)

This method sorts or rearrange the values inside the array according to a condition.

For example here we can sort them from smaller to higher.

var numbers = [10, 24, 3, 73, 5]
numbers.sort(by: { $0 < $1 })
print(numbers) 
// Output: [3, 5, 10, 24, 73]
Enter fullscreen mode Exit fullscreen mode

.first

This property returns the first element of our array.

var numbers = [3, 63, 27]
print(numbers.first) 
// Output: 3
Enter fullscreen mode Exit fullscreen mode

.last

This property returns the last element of the array.

var numbers = [3, 63, 27]
print(numbers.last) 
// Output: 27
Enter fullscreen mode Exit fullscreen mode

.removeFirst()

This method removes the first element of the array.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.removeFirst()
print(groceryList) 
// Output: ["Apples", "Pasta"]
Enter fullscreen mode Exit fullscreen mode

.removeLast()

This method removes the last element of the array.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.removeLast()
print(groceryList) 
// Output: ["Onions", "Apples"]
Enter fullscreen mode Exit fullscreen mode

.firstIndex(where:)

This method returns the index of the first value that satisfies a condition.

var numbers = [3, 63, 27]
let firstIndex = numbers.firstIndex(where: { $0 > 10 })
print(firstIndex!) // Output: 1
Enter fullscreen mode Exit fullscreen mode

.shuffled()

This method returns a new array with the elements shuffled.

var numbers = [3, 63, 27]
let shuffled = numbers.shuffled()
print(shuffled) 
// Output: [27, 3, 63] (order will vary)
Enter fullscreen mode Exit fullscreen mode

.reverse()

This method reverses the order of the elements in the array.

var groceryList = ["Onions", "Apples", "Pasta"]
groceryList.reverse()
print(groceryList) 
// Output: ["Pasta", "Apples", "Onions"]
Enter fullscreen mode Exit fullscreen mode

.allSatisfy(_:)

This method returns true if all elements satisfy a condition, otherwise false.

var numbers = [3, 63, 27]
let allGreaterThanTen = numbers.allSatisfy { $0 > 10 }
print(allGreaterThanTen) // Output: false
Enter fullscreen mode Exit fullscreen mode

.contains(_:)

This method checks if the array contains a specific element.

var numbers = [3, 63, 27]
let containsTwentySeven = numbers.contains(27)
print(containsTwentySeven) 
// Output: true
Enter fullscreen mode Exit fullscreen mode

.isEmpty

This property checks if the array is empty and returns a boolean result.

var numbers = [3, 63, 27]
print(numbers.isEmpty) // Output: false
Enter fullscreen mode Exit fullscreen mode

Resources

If you want a Cheat Sheet with some of this methods and properties, feel free to save or download this image. If you share it please do not delete or hide my name 🫶🏻​

Cheat sheet with some of the methods and properties of arrays

Also if you want to keep learning more about this I highly recommend checking the official documentation and courses here


Want to keep learning about Swift?

This a full series on Swift 101, next chapter will be the second part of Collections where I will share about Sets, Tuples and Dictionaries, so I hope to see you there!

If you enjoyed this, please share, like, and comment. I hope this can be useful to someone and that it will inspire more people to learn and code with Swift

Top comments (0)