Searching an array
A row of lockers can be rebuilt, but more often people come to it with a question. What is in the first locker and in the last one? Is the item you need anywhere, and under which number? To answer, you do not touch the row; you only look into the lockers.
You already know how to get some of the answers by index. The last element sits at the index count - 1. But an empty array has a count of 0, and scores[scores.count - 1] asks for the element at index -1. There is no such locker, and the program crashes with Index out of range.
An array has ready-made tools for such questions. They do not crash the program even on an empty row:
let scores = [7, 9, 4, 9]
print(scores.first ?? 0, scores.last ?? 0) // 7 9
print(scores.contains(9), scores.contains(5)) // true false
if let index = scores.firstIndex(of: 9) {
print(index) // 1
}
print(scores.max() ?? 0, scores.min() ?? 0) // 9 4Let's go through the program line by line:
firstandlastgive the first and the last element:7and9. The answer comes in an optional box, so it is opened with?? 0.contains(9)answerstrue: there is a nine in the row. There is no five, andcontains(5)givesfalse.firstIndex(of: 9)finds the first nine at index1. The box is not empty, soif letruns its body, and the program prints1.max()andmin()find the largest and the smallest element:9and4.
The array scores is declared with let, and the program still compiles: none of these questions changes the array.
Four questions for an array
first and last
first is the first element of the array, last the last one. They work the same way on a string, only there they give a character. You write them without parentheses, like count.
contains
contains(9) goes through the row and answers whether it has a 9. The answer is a plain Bool, and you can put it straight into an if condition. If you need the element's place rather than a yes-or-no answer, you take firstIndex(of:).
firstIndex(of:)
firstIndex(of: 9) walks the row from the start and returns the index of the first nine it finds. The method stops there and does not look for the second nine, at index 3. The index it finds is useful for replacing the element through square brackets or removing it with remove(at:).
max() and min()
max() returns the largest element, min() the smallest. You write them with empty parentheses, while first and last take none.
When there is no answer
first, last, firstIndex(of:), max() and min() return an optional. An empty array has no first element, and the number you look for may not be in the row. Then an empty box comes instead of a value—nil. That is why you unwrap the value with ?? or if let, as in the first program.
Here the locker picture is inaccurate. In a changing room the row stands even when every locker is empty. But an empty array is a row without a single locker, and it has no first locker:
let empty = [Int]()
print(empty.first ?? 0, empty.max() ?? 0) // 0 0
print(scores.firstIndex(of: 5) == nil) // trueemptyhas neither a first element nor a largest one, and both??put in0.- There is no five in
scores, sofirstIndex(of: 5)givesnil, and the comparison withnilprintstrue. With that answer, theif letfrom the first program would skip its body.
contains does not return an optional: the question "is it there?" always has an answer, true or false.
Interviewers may ask how scores.first differs from scores[0]. The answer: on an empty array scores[0] crashes the program, while first returns nil.
Common mistake
The spread of marks computed as the largest minus the smallest:
let spread = scores.max() - scores.min() // ✗error: binary operator '-' cannot be applied to two 'Int?' operandsThe program does not compile. max() and min() return Int?, and you cannot subtract one box from another: either of them may turn out empty. Open both boxes first, for example with one if let:
if let best = scores.max(), let worst = scores.min() {
print(best - worst) // 5
}Inside the body, best and worst are plain numbers, 9 and 4, and the difference 5 prints without errors.
Key points
firstandlastgive the elements at the ends of the row, andmax()andmin()the largest and the smallest.containsanswers with aBool, andfirstIndex(of:)gives the index of the first match.first,last,firstIndex(of:),max()andmin()return an optional; you unwrap it with??orif let.- These questions do not change the array, so they work on an array declared with
lettoo.