# Performance, functional programming and collections in Swift

Functional programming is often done in Swift and so easy that it could easily hit performance. Iterating over large collections and performing actions like `filter`

or `map`

is common and should be used wisely.

Performance is often decreasing when these methods are combined, like a `filter`

followed by `first`

. A list of best practices.

### Prefer `contains`

over `first(where:) != nil`

Verifying if an object exists in a collection can be done in multiple ways. Make sure to use `contains`

for best performance.

#### Best practice

`let numbers = [0, 1, 2, 3]`

numbers.contains(1)

#### Bad practice

`let numbers = [0, 1, 2, 3]`

numbers.filter { number in number == 1 }.isEmpty == false

numbers.first(where: { number in number == 1 }) != nil

### Prefer checking `isEmpty`

over comparing `count`

to zero.

The best way to describe the reasoning for this is by quoting the isEmpty documentation.

When you need to check whether your collection is empty, use the isEmpty property instead of checking that the count property is equal to zero. For collections that don’t conform to RandomAccessCollection, accessing the count property iterates through the elements of the collection.

#### Best practice

`let numbers = []`

numbers.isEmpty

#### Bad practice

`let numbers = []`

numbers.count == 0

### Checking for an empty String with `isEmpty`

A `String`

in Swift can be seen as a collection of Characters. This means that the above performance practice counts for strings as well and `isEmpty`

should be used to check for an empty string.

#### Best practice

`myString.isEmpty`

#### Bad practice

`myString == ""`

myString.count == 0

### Get the first object matching a condition

Iterating over a collection to get the first object matching a given condition can be done using a `filter`

following by `first`

, but best practice is to use `first(where:)`

instead.

The latter stops iterating over the collection as soon as the condition is met for the first time. The `filter`

would continue iterating over the whole collection, even though it might already hit an object matching the condition.

Obviously, the same counts for `last(where:)`

.

#### Best practice

`let numbers = [3, 7, 4, -2, 9, -6, 10, 1]`

let firstNegative = numbers.first(where: { $0 < 0 })

#### Bad practice

`let numbers = [3, 7, 4, -2, 9, -6, 10, 1]`

let firstNegative = numbers.filter { $0 < 0 }.first

### Getting the minimum or maximum element in a collection

The minimum element in a collection can be found after sorting it and selecting the first object. The same counts for the maximum element. This, however, requires to sort the whole array first. Using the `min()`

and `max()`

methods is best practice in this case.

#### Best practice

`let numbers = [0, 4, 2, 8]`

let minNumber = numbers.min()

let maxNumber = numbers.max()

#### Bad practice

`let numbers = [0, 4, 2, 8]`

let minNumber = numbers.sorted().first

let maxNumber = numbers.sorted().last

### Making sure all objects match a condition

It’s easy to use a `filter`

combined with `isEmpty`

to verify that all objects in a collection match a given condition. With SE-0207 introduced in Swift 4.2 we can now use `allSatisfy(_:)`

to verify that every element of a collection matches a given condition.

#### Best practice

`let numbers = [0, 2, 4, 6]`

let allEven = numbers.allSatisfy { $0 % 2 == 0 }

#### Bad practice

`let numbers = [0, 2, 4, 6]`

let allEven = numbers.filter { $0 % 2 != 0 }.isEmpty

### Using SwiftLint to ensure best practices

Most of these examples are implemented in SwiftLint and help you to ensure that these best practices are used.

*Originally published at **SwiftLee**.*