The collections included in Swift allow us the use of higher order functions, that is, functions that take other functions and use them to perform transformations on datasets. For example, an array provides us with the filter
, map
, and reduce
methods.
As previously explained, the preceding code represents an imperative version of array filtering. We can achieve the same goal with a functional approach using the filter
method included in all the types that conform to the Sequence
protocol. The Array<Element>
struct conforms to the Sequence
protocol and many other protocols. In Swift versions prior to 3, the Sequence
protocol was named SequenceType
.
As it happens in most modern languages, Swift supports closures, which are also known as anonymous functions. Closures are self-contained blocks of functionality that we can pass around and use within our code as functions without names. Closures automatically capture everything we reference, such as variables and functions that aren't defined within the closure. Closures in Swift are similar to blocks in Objective-C.
The following lines use a closure as an argument for the filter
method to generate the array with the numbers divisible by 5
. The closure is the code surrounded with braces ({}
), and it uses the in
keyword to separate the argument (number: Int)
and the return type (Bool
) for the closure from its body. The code file for the sample is included in the swift_3_oop_chapter_07_08
folder:
var filteredNumbers = numbersList.filter({
(number: Int) -> Bool in
return NumberFunctions.isDivisibleBy5(number: number)
})
print(filteredNumbers)
The code calls the filter
method for the previously defined numbersList Array<Int>
. This method creates and returns a new Array<Int>
that contains only those elements of numbersList Array<Int>
for which the Bool
value returned by the specified closure returns true
. In this case, the closure receives a number
value of the Int
type and returns the result of calling the NumberFunctions.isDivisibleBy5
type method with number
as the number argument.
The following lines add a new filteredBy
method to the existing NumbersWorker
class. The method specifies a function type for the condition
argument and then uses the function type within the closure that the filter
method calls. This way, we are able to call this method with the function name that we want to receive an Int
value and return Bool
to evaluate which members of the original array are returned in the resulting array. The code file for the sample is included in the swift_3_oop_chapter_07_09
folder:
open func filteredBy(condition: (Int) -> Bool) -> [Int] { return numbersList.filter({ (number: Int) -> Bool in return condition(number) }) }
The next lines create a numbersList2
array of Int
and then pass it as an argument to the initializer of the NumbersWorker
class. The last line calls the worker2.applyFunctionToNumbers
method with the NumberFunctions.isNumberDivisibleBy5
type method as an argument. The code file for the sample is included in the swift_3_oop_chapter_07_09
folder:
var numbersList2 = [-30, -29, -47, 10, 30, 50, 80] var worker2 = NumbersWorker(numbers: numbersList) var filteredNumbers2 = worker2.filteredBy (condition: NumberFunctions.isDivisibleBy5) print(filteredNumbers2)
The following screenshot shows the results of executing the previous lines in the Playground:
3.22.61.179