Fast Lane to Swift collections — Part-1: Arrays

Hetashree Bharadwaj
Mindful Engineering
9 min readNov 27, 2019

Today we are going to take a quick but detailed look at Swift collections, Here is most generous definition of it

A sequence whose elements can be traversed multiple times, nondestructively, and accessed by an indexed subscript, It is known as collection.

Let’s jump on it.

Collection Types

There are three types of collection in swift language : Array, Sets, Dictionary.

Collections are ways to group related items together, each have their own applications.

Arrays let us create ordered list of related group items.

Sets allow to create the distinct unordered list, You can not have duplicate entries In your group(a set).

Dictionaries are unordered collections of key-value pairs. Dictionaries are versatile and can be used in more complicated requirements,

Here each group solves particular type of grouping problems and each type is crucial in their own.

Collections are immensely important in day to day programming. Grouping related items and further manipulating the grouping is the heart of working with data.

Swift offers us many ways to create mutable(changeable) and immutable(not changeable) variants of collections.

The mutable collection means after it’s created, we can add, remove or change items in the grouping while with immutable collections, its size & contents cannot be changed.

It’s good practice to create immutable collections in all cases where the collection does not need to change.

To make sure we don’t get exhausted with all of the good stuff in a single article, I will be covering it in a series of posts.

In this post, we will cover Arrays. In upcoming posts, we will cover Sets & dictionaries.

Happy Reading! 😊

Working with Arrays:

Swift Arrays are created using Generic type Element. Array is defined as Array<Element> with Element being single type used in the collection. Once you define the type of array, you can’t add any other type of data to the array If done it will generate a compile-time error.

Creating Arrays:

Arrays are easy to create. You can create an empty array of type explicit set or allow the swift compiler to infer the type (based on context).

In following snippet the type of arrayInts variable is inferred to be an integer from type of initializer.

var arrayInts = [Int]()print(“arrayInts is of type [Int] with \(arrayInts.count) items.”)print(“arrayInts is of type [Int] with \(arrayInts.capacity) capacity.”)Output:arrayInts is of type [Int] with 0 items.arrayInts is of type [Int] with 0 capacity.

Alternatively, if context already provide type information and such a function argument or already typed variable , you can create an empty array with empty pair of brackets [ ] .

var emptyArray = [ ]

Creating Array With Default Values :

You can also create an array and initialize it with values. In fact there are many ways to define an array with initial values. The most common way to define an array is array literal.

In following snippet, I am defining the list of Mac OS versions as an array literal and assigning the list to create macOS array.

Example 1var arrayMacOS = [“Sierra”, “Mojave”, “Catalina”]print(arrayMacOS)Output:[“Sierra”, “Mojave”, “Catalina”]Example 2var arrayInts = [Int]()arrayInts.append(1)arrayInts.append(2)arrayInts.append(3)print(“arrayInts is of type [Int] with \(arrayInts) items.”)Output:arrayInts is of type [Int] with [1, 2, 3] items.

Here is a lesser known way to create an array while defining it’s initial size and default values. It would be interesting to set the string and default each value in the list to “macOS”.

var arrayOS = Array(repeating: “macOS”, count: 10)print(arrayOS)Output:[“macOS”, “macOS”, “macOS”, “macOS”, “macOS”, “macOS”, “macOS”, “macOS”, “macOS”, “macOS”]

You can also concat two arrays and get single array out of it as follows:

var arrayMacOS = [“Sierra”, “Mojave”, “Catalina”]var arrayOS = [“iOS”, “macOS”, “watchOS”, “tvOS”]var arrays = arrayMacOS + arrayOSprint(arrays)Output:[“Sierra”, “Mojave”, “Catalina”, “iOS”, “macOS”, “watchOS”, “tvOS”]

Manipulating Arrays:

  • Now we know how to create arrays, Let’s try operations with it. Arrays have several methods & properties to allow you to access values or even to insert or remove values. You can determine how many elements are in an array using count property. If you want to know the state of an array like if it has any element(s) or not at that time you can use the isEmpty property, which will provide a boolean value.
var arrayOS = [“iOS”, “macOS”, “watchOS”, “tvOS”]if arrayOS.isEmpty {print(“array OS are empty.”)} else {print(“array OS has \(arrayOS.count) values.”)}Output:array OS has 4 values.
  • Adding and removing values are straightforward with arrays. You can add value to the end of an array using the append() method. Or you can insert a value into an array at a specified index using the insert() method. alternatively you can use “+=“ (addition assignment operator) to insert a value in array.
var shoppingList = [“Baking Powder”]shoppingList.append(“Chocolate Spread”)shoppingList.insert(“Cheese”, at: 1)shoppingList += [“Butter”]print(shoppingList)Output:[“Baking Powder”, “Cheese”, “Chocolate Spread”, “Butter”]
  • With swift Arrays, we can access an index to retrieve or replace its value.
var shoppingList = [“Baking Powder”, “Chocolate Spread”]shoppingList[1] = “Butter”print(shoppingList)Output:[“Baking Powder”, “Butter”]
  • You can retrieve subarray using subscript syntax.
var shoppingList = [“Baking Powder”, “Butter”,”Cheese”, “Chocolate Spread”]let list = shoppingList[0…2]print(list)Output:[“Baking Powder”, “Butter”, “Cheese”]
  • Finally, you can iterate over an array using the for-in syntax.
var shoppingList = [“Baking Powder”, “Butter”,”Cheese”, “Chocolate Spread”]for values in shoppingList {print(values)}Output:Baking PowderButterCheeseChocolate Spread
  • In the above example, if you need the index along with the item, you can use the enumerate() method to loop over an array. Each item of an array is returned along with its index using a tuple to store both values.
for (index, value) in shoppingList.enumerated() {print(“index: \(index + 1) = \(value)”)}Output:index: 1 = Baking Powder 
index: 2 = Butter
index: 3 = Cheese
index: 4 = Chocolate Spread
  • You can remove elements from an array using removeAtIndex or removeLast. removeAtIndex removes an element at specific index. while removeLast can be used to remove the last element of the array. We can also pop the last element from array using popLast. In similar fashion one can pop the first element from array using popFirst.
var arrayOfInts = [0, 1, 2, 3, 4, 5]arrayOfInts.removeAtIndex(6)print(arrayOfInts)arrayOfInts.removeLast()print(arrayOfInts)arrayOfInts.popLast()print(arrayOfInts)arrayOfInts.popFirst()print(arrayOfInts)Output:[0, 1, 2, 3, 4] // remove at index 6[0, 1, 2, 3] // remove last element[0, 1, 2, 3] // pop last element[1, 2, 3] // pop first element
  • dropLast(), dropFirst(), prefix, suffix are the ArraySlice methods.
  • ArraySlice holds a strong reference of its array. It means that we should pay attention how we use the slice to avoid troubles with the memory.
  • You can drop elements from an array using dropLast.
let numbers = [1, 2, 3, 4, 5]print(numbers.dropLast(2))print(numbers.dropLast(10))Output:[1, 2, 3][]
  • You can create subsequence from last index of the array using suffix.
let numbers = [1, 2, 3, 4, 5]print(numbers.suffix(2))print(numbers.suffix(10))Output:[4, 5][1, 2, 3, 4, 5]
  • You can create subsequence from start of the collection up to, but not including the specified position using prefix.
let numbers = [10, 20, 30, 40, 50, 60]if let i = numbers.firstIndex(of: 40) {print(numbers.prefix(upTo: i))}Output:[10, 20, 30, 40]
  • Following example iterates over the Unsafe Buffer Pointer. “withUnsafeBufferPointer” will not store or return the pointer for later use.
let number = [1, 2, 3, 4, 5]let sum = number.withUnsafeBufferPointer { buffer -> Int invar result = 0for i in stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) {result += buffer[i]}print(result)}Output :9
  • Last will return the last element of collection.
let numbers = [10, 20, 30, 40, 50]if let lastNumber = numbers.last {print(lastNumber)}if let lastNum = numbers.last(where: { $0 < 20 }) {print(“The last number is \(lastNum).”)}Output:50 // for last number10
  • FirstIndex will return the first index of each element of the group satisfies the given predicate.
let students = [“Kofi”, “Abena”, “Peter”, “Kweku”, “Akosua”]if let i = students.firstIndex(where: { (xy) -> Bool inxy.hasPrefix(“A”)}){print(“\(students[i]) starts with ‘A’!”)}Output:Abena starts with ‘A’!
  • shuffled will return the elements in random order.
let numbers = 0…9let shuffledNumbers = numbers.shuffled()Output:[8, 9, 4, 3, 2, 6, 7, 0, 5, 1]
  • You can replace the range of elements using replaceSubrange. In it, the number of elements doesn’t need to match the numbers of elements being removed.
var number = [10, 2, 3, 4, 5]number.replaceSubrange(1…3, with: repeatElement(1, count: 5))print(number)OutPut:[10, 1, 1, 1, 1, 1, 5]
  • You can exchange the values at the specific position using swapAt.
  • The indices that are valid for subscripting the collection, in ascending order.

MAP

Map is used to when you want to apply the same operations to each element of a collection. It takes a single argument in the form of mapping and returns an array with the transformed elements of the input sequence.

Example 1:Convert Meters to Feetlet meters = [10.0, 22.0, 55.0, 74.0]let feet = meters.map { $0 * 3.281}print(“Meters converted to feet: \(feet)”)Output:Meters converted to feet: [32.81, 72.182, 180.455, 242.794]Example 2: Make the planet names capitalizedlet planetNames = [“mars”, “jupiter”, “mercury”, “saturn”, “earth”, “neptune”, “uranus”, “venus”]let capitalizedPlanetNames = planetNames.map { $0.capitalized }print(“Planet names capitalized: \(capitalizedPlanetNames)”)Output:Planet names capitalized: [“Mars”, “Jupiter”, “Mercury”, “Saturn”, “Earth”, “Neptune”, “Uranus”, “Venus”]

Filter

Filter is used when you want to have a result with only elements that match a condition.

Example 1: Filter only the planets that start with the letter “M”let filteredPlanetNames = planetNames.filter {$0.prefix(1).uppercased() == “M”}print(“Count of filtered planet names: \(filteredPlanetNames.count)”)Output:Count of filtered planet names: 2Example 2: Filter the address array to only addresses from zip code 1200let filteredAddresses = addresses.filter {$0.zipcode == 1200}print(“Count of filtered addresses: \(filteredAddresses.count)”)Output:Count of filtered addresses: 1

Reduce

Reduce is used when you want to combine all elements in a collection into one value.

//Sum of numbers let numbers = [5, 3, 2, 6, 10, 23, 01, 43, 5, 7, 8, 9]let sumOfNumbers = numbers.reduce(0, {$0 + $1})print(“Sum of numbers : \(sumOfNumbers)”)Output:Sum of numbers: 122

Sorted

When calling sorted() on an array, it will return a new array that has the items sorted in ascending order.

Example 1 : Sorted numbers ascendinglet numbers = [5, 3, 2, 6, 10, 23, 01, 43, 5, 7, 8, 9]let sortedNumbersAscending = numbers.sorted()print(“Sorted numbers ascending: \(sortedNumbersAscending)”)Output:Sorted numbers ascending: [1, 2, 3, 5, 5, 6, 7, 8, 9, 10, 23, 43]Example 2 : Sorted numbers descendinglet sortedNumbersDescending = numbers.sorted { (a, b) -> Bool ina > b}print(“Sorted numbers descending — version 1: \(sortedNumbersDescending)”)Output:Sorted numbers descending: [43, 23, 10, 9, 8, 7, 6, 5, 5, 3, 2, 1]

FlatMap

A flatMap flattens an array, containing more arrays with the same content type, into one “flat” array. If you’re using a flatMap on a “flat” array, it will split all items in that array (taken they’re of the same type), as the function flattens all sub-collections into one single collection.

let arrayDict = [ [1,5,8,9,7,8,9], [1,5,8,9,7,8,9] ]let arrFlatMap = arrayDict.flatMap { $0 }print(“Array ion flatMap: \(arrFlatMap)”)Output:arrFlatMap: [1, 5, 8, 9, 7, 8, 9, 1, 5, 8, 9, 7, 8, 9]

CompactMap

CompactMap can be “used as flatMap”, when you work with optional values. CompactMap can be used to either give you nil-values (which flapMap can’t), but also to filter out nil-values from a sequence.

Example 1let possibleNumbers = [“1”, “2”, “three”, “///4///”, “5”]let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }print(compactMapped)Output:[1, 2, 5]Example 2let arrayWithNillVal = [1,2,5,8,9,nil,nil,8,9,9,9,9]let arrayCompactMap = arrayWithNillVal.compactMap ({ $0 })print(arrayCompactMap)Output:[1, 2, 5, 8, 9, 8, 9, 9, 9, 9]

Chaining

Another great thing about higher order functions is that we can combine(chain) them. This means that what would normally have taken many lines of code can be reduced to a single line.

//An array of sorted capitalized planet nameslet planetNames = [“mars”, “jupiter”, “mercury”, “saturn”, “earth”, “neptune”, “uranus”, “venus”]let sortedCapitalizedPlanetNames = planetNames.map { $0.capitalized }.sorted()print(“Sorted capitalized plane names: \(sortedCapitalizedPlanetNames)”)Output:Sorted capitalized plane names: [“Earth”, “Jupiter”, “Mars”, “Mercury”, “Neptune”, “Saturn”, “Uranus”, “Venus”]

Final Notes

Getting to understand higher order functions, and learning how to use them in real life projects, especially chained, may require some practice. When there’s a lot happening “behind the scenes”, things sometimes seems like black magic, but when you get your head around them, they become really useful. So if you are not already using higher order functions, now is a great time to start using them and get them under your skin. You will thank yourself later (as will future developers on your project), as it saves both time and reduces boiler plate code.

--

--

Hetashree Bharadwaj
Mindful Engineering

Passionate App developer with expertise on Swift and Flutter, Novice writer as you might already have found out.