In Swift, what's the cleanest way to get the last two items in an Array?

With Swift 5, according to your needs, you may choose one of the following patterns in order to get a new array from the last two elements of an array.


#1. Using Array's suffix(_:)

With Swift, objects that conform to Collection protocol have a suffix(_:) method. Array's suffix(_:) has the following declaration:

func suffix(_ maxLength: Int) -> ArraySlice<Element>

Returns a subsequence, up to the given maximum length, containing the final elements of the collection.

Usage:

let array = [1, 2, 3, 4]
let arraySlice = array.suffix(2)
let newArray = Array(arraySlice)
print(newArray) // prints: [3, 4]

#2. Using Array's subscript(_:)

As an alternative to suffix(_:) method, you may use Array's subscript(_:) subscript:

let array = [1, 2, 3, 4]
let range = array.index(array.endIndex, offsetBy: -2) ..< array.endIndex
//let range = array.index(array.endIndex, offsetBy: -2)... // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints: [3, 4]

myList[-2:]

Yes, I have an enhancement request filed asking for negative index notation, and I suggest you file one too.

However, you shouldn't make this harder on yourself than you have to. The built-in global suffix function does exactly what you're after:

let oneArray = ["uno"]
let twoArray = ["uno", "dos"]
let threeArray = ["uno", "dos", "tres"]

let arr1 = suffix(oneArray,2) // ["uno"]
let arr2 = suffix(twoArray,2) // ["uno", "dos"]
let arr3 = suffix(threeArray,2) // ["dos", "tres"]

The result is a slice, but you can coerce it to an Array if you need to.


In Swift 2, you can extend CollectionType. Here's an example (borrowing from Rob Napier's answer):

extension CollectionType {
    func last(count:Int) -> [Self.Generator.Element] {
        let selfCount = self.count as! Int
        if selfCount <= count - 1 {
            return Array(self)
        } else {
            return Array(self.reverse()[0...count - 1].reverse())
        }
    }
}

You can use it on any CollectionType. Here's Array:

let array = ["uno", "dos", "tres"]
print(array.last(2)) // [dos, tres]

Here's CharacterView:

let string = "looking"
print(string.characters.last(4)) // [k, i, n, g]

(Note that my example returns an Array in all cases, not the original collection type.)