Extending Swift Arrays

Array is one of the most used collection types in Swift. Although it is extremely powerful (and the language provides much faster array iterations compared to Objective-C) it lacks many of the capabilities we were used to when working with NSArray and NSMutableArray collection types.

An easy workaround for the developer in order to deal with the missing functionality is to just cast Swift arrays to NSArray or its mutable counterpart. Another -more sophisticated- solution is to add this functionality to Swift Array, using Extensions. Extensions in Swift are what Categories are in Objective-C, an easy way to extend an existing object type with additional functionality.

Swift 2.0 added the capability to find an index of an item within an Array but it didn’t added a method to remove an object without knowing its index. Adding this is easy with an Array Extension:

import Foundation
extension Array where Element: Equatable {
mutating func removeObject(object: Element) {
guard let index = self.indexOf(object) else { return }
self.removeAtIndex(index)
}

mutating func removeObjects(array: [Element]) {
for object in array {
self.removeObject(object)
}
}
}

Note that we are using mutating func here, because these functions change the value of our object. The first method finds the index of an object and removes it, while the second one does the same for multiple object.

Let’s say we need a sample method that returns a random object of our Array:

func sample() -> Element {
let randomIndex = Int(rand()) % count
return self[randomIndex]
}

Nothing tricky here. Let’s see a more complex example. Let’s assume that we need to shuffle our Array. We will add to methods for shuffling. One that shuffles the Array and one that returns a copy of our Array with the objects shuffled. The method that shuffles the existing Array needs to be a mutating func, while the method that returns a new Array doesn’t

mutating func shuffle() {
if count < 2 { return }
for index in 0..<count — 1 {
let newIndex = Int(arc4random_uniform(UInt32(count — index))) + index
guard index != newIndex else { continue }
swap(&self[index], &self[newIndex])
}
}

func shuffled() -> [Element] {
var list = self
for index in 0..<list.count {
let newIndex = Int(arc4random_uniform(UInt32(list.count-index))) + index
if index != newIndex {
swap(&list[index], &list[newIndex])
}
}
return list
}

You can download a sample project with the extension here. Feel free to use it in your project or add extra functionality to it. Just the extension is also available in this Gist.

Related


Originally published at blog.typpz.com on January 24, 2016.