Experimental approach of Performance of map, filter vs for-loops in Swift
Introduction:
In Swift programming there is a paradigm called functional programming. Map, filter and reduce are examples of this paradigm. In swift, we use these functions to loop over collections without using a for-loop.
The Basic Setup:
Hardware:
The data shown here was all generated from my personal Macbook Pro (macOS Catalina v10.15.6, 2.5 GHz Quad-Core Intel Core i5 with16 GBs 600 MHz DDR3)
Project Setup
In terms of software, I used Xcode v11.3.1 with the default Swift v5.1.3. For the purpose of comparisons, I created a Project with Unit Tests. I wrote many unit tests to measure the performance of each function. I ran each unit test of map, filter and reduce function vs loops twice. Each unit test used an array with 10000000 of integer numbers.
Experiments:
Map vs Loop
In this experiment, the test converts the first 1000000 to its square value.
Code:
func testMapPerformance() {
self.measure {
let newNumbers = input.map(square)
}
}
func square(number:Int) -> Int {
return number * number
}
func testLoopPerformance() {
var newNumbers = [Int]()
self.measure {
for number in input {
let newNumber = number * number
newNumbers.append(newNumber)
}
}
}
Results:
The time of normal for-loop is greater than map function.
Test | Map | Loop |
---|---|---|
Test #1 | 2.092 | 2.846 |
Test #2 | 2.076 | 2.886 |
Filter vs Loop
In this experiment, the test filters the even values of the first 1000000 values.
Code:
func testFilterPerformance () {
self.measure {
let evenNumbers = input.filter(isEven)
}
}
func isEven(number: Int) -> Bool {
return number % 2 == 0
}
func testLoopPerformance () {
var evenNumbers = [Int]()
self.measure {
for number in input {
if (number % 2 == 0) {
evenNumbers.append(number)
}
}
}
}
Results:
The time of normal for-loop is greater than filter function.
Test | Filter | Loop |
---|---|---|
Test #1 | 1.823 | 2.117 |
Test #2 | 2.093 | 2.951 |
Reduce vs Loop
In this experiment, the test obtains the sum of the first 1000000 values.
Code:
func testReducePerformance() {
self.measure {
let sum = input.reduce(0, reduceSum)
}
}
func reduceSum (sum: Int, element: Int) -> Int {
return sum + element
}
func testLoopPerformance () {
var sum = 0
self.measure {
for number in input {
sum += number
}
}
}
Results:
The time of normal for-loop is less than the reduce function.
Test | Reduce | Loop |
---|---|---|
Test #1 | 1.472 | 1.224 |
Test #2 | 1.480 | 1.338 |
Conclusions:
Map and Filter are more efficient than loops with large data, but the difference isn’t significant. However, it is a good idea to know about functional programming, because it is very used in reactive programming.
Full source code:
The code that was used in these experiments can be found on GitHub.