Higher Order Functions - Swift Programming
HigherOrder Functions
- Introduction
- Sort
- Map
- Reduce
- Filter
Introduction:
What is Function?
Functions are self-contained chunks of code that perform a specific task. Function name should give clarity that what it does, and that name is used to “call” the function to perform its task when needed.
Every function in Swift has a type, consisting of the function’s parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions.
Functions can also be written within other functions to encapsulate useful functionality within a nested function scope.
If the entire body of the function is a single expression, the function implicitly returns that expression.
What is HigherOrder Function?
A higher order function is a function that accepts
- one or more functions as an input (or)
- returns a value of function type as output (or)
- doing both
func sampleFunction() { }
Void
. This is simply an empty tuple, which is written as ()
sampleFunction have no params and Void as return type (which means no return type).
So the function type of the sampleFunction would be mentioned as "() -> Void", where () represents no params and Void represents no return values
function type as output param
The below function have no params and "() -> Void" as return type. So it can return sampleFunction
func higherOrderFunctionReturningFunction() -> () -> Void {
print(#function, "With in function print statement")
return sampleFunction
}
higherOrderFunctionReturningFunction() // prints - higherOrderFunctionReturningFunction() With in function print statement
function type as input param
The below function have params "() -> Void" and Void as return type
func higherOrderFunctionAcceptingFunctionAsParams(functionParam: () -> Void) {
print(#function, "With in function print statement")
functionParam()
}
Usage:
higherOrderFunctionAcceptingFunctionAsParams { () -> Void in
print("With in closure - mentioning function type - print statement")
}
higherOrderFunctionAcceptingFunctionAsParams {
print("With in closure - without mentioning function type - print statement")
}
The above two wouldn't executes their inner blocks until they called in function (calling non-escaping closure), as below
func higherOrderFunctionAcceptingFunctionAsParams(functionParam: () -> Void) {
print(#function, "With in function print statement")
functionParam()
}
Output:
higherOrderFunctionAcceptingFunctionAsParams(functionParam:) With in function print statement
With in closure - mentioning function type - print statement
higherOrderFunctionAcceptingFunctionAsParams(functionParam:) With in function print statement
With in closure - without mentioning function type - print statement
function type as input & output param
The below function have params "() -> Void" and "() -> Void" as return type
func higherOrderFunctionDoingBoth(functionParam: () -> Void) -> () -> Void {
print(#function, "With in function print statement")
functionParam()
return sampleFunction
}
Usage:
higherOrderFunctionDoingBoth { () -> Void in
print("With in closure - mentioning function type - print statement")
}
higherOrderFunctionDoingBoth {
print("With in closure - without mentioning function type - print statement")
}
Output:
higherOrderFunctionDoingBoth(functionParam:) With in function print statement
With in closure - mentioning function type - print statement
higherOrderFunctionDoingBoth(functionParam:) With in function print statement
With in closure - without mentioning function type - print statement
Swift have default higher-order functions.
- Sort
- Map
- CompactMap
- FlatMap
- Reduce
- Filter
Sort:
Sorts the collection in place. You can sort any mutable collection of elements that conform to the Comparable
protocol by calling this method.
mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows
Elements are sorted in ascending order by default
var numbers = [1, 2, 5, 3, 8]numbers.sort()print(numbers) // [1, 2, 3, 5, 8]
numbers.sort(by: >)print(numbers) // [8, 5, 3, 2, 1]
The sorting algorithm is not guaranteed to be stable. A stable sort preserves the relative order of elements that compare equal.
Complexity: O(n log n), where n is the length of the collection.
var getEvenNumbersFirst = [8, 2, 5, 1, 3]
getEvenNumbersFirst.sort { (valueOne, valueTwo) -> Bool in
return valueOne % 2 == 0
}
print(getEvenNumbersFirst) // [2, 8, 5, 1, 3]
var getOddNumbersFirst = [8, 2, 5, 1, 3]
getOddNumbersFirst.sort { (valueOne, valueTwo) -> Bool in
return valueOne % 2 != 0
}
print(getOddNumbersFirst) // [3, 1, 5, 8, 2]
Map:
map
Returns an array containing the results of mapping the given closure over the sequence’s elements.
func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
A mapping closure. transform
accepts an element of this sequence as its parameter and returns a transformed value of the same or of a different type.
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map { $0.lowercased() } // ["vivien", "marlon", "kim", "karl"]
let numbers = ["1", "2", "5", "3", "Sun"]
let numbersMapped = numbers.map { Int($0) } // [Optional(1), Optional(2), Optional(5), Optional(3), nil]
compactMap
Returns an array containing the non-nil
results of calling the given transformation with each element of this sequence.
func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
A closure that accepts an element of this sequence as its argument and returns an optional value.
An array of the non-nil
results of calling transform
with each element of the sequence.
an array of non-optional values when your transformation produces an optional value.
let numbersCompactMapped = numbers.compactMap { Int($0) } // [1, 2, 5, 3]
Complexity: O(m + n), where n is the length of this sequence and m is the length of the result.
flatMap
Returns an array containing the concatenated results of calling the given transformation with each element of this sequence.
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
A closure that accepts an element of this sequence as its argument and returns a sequence or collection.
The resulting flattened array.
receive a single-level collection when your transformation produces a sequence or collection for each element.
In this example, note the difference in the result of using map
and flat
with a transformation that returns an array
let numbers = [1, 2, 3, 4]let mapped = numbers.map { Array(repeating: $0, count: $0) }// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]] let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
In fact, s
is equivalent to Array(s
.
Complexity: O(m + n), where n is the length of this sequence and m is the length of the result.
Reduce:
Returns the result of combining the elements of the sequence using the given closure.
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result
initial Result
is passed to next Partial Result
the first time the closure is executed.next Partial Result
closure or returned to the caller.initial Result
.reduce(_: _:)
method to produce a single value from the elements of an entire sequence.var numbers = [1, 2, 5, 3, 8]
let numbersSum = numbers.reduce(0) { (partialResult, nextValue) in
partialResult + nextValue
}
Filter:
func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]
is Included
allowed.let names = ["Sunil", "Siri", "Sunil N", "Sunny"]
let shortNames = names.filter { $0.count <= 5 } // ["Sunil", "Siri", "Sunny"]
Reference Links:
- https://gist.github.com/ixcoder001/3b449e39e857077957444e4c1121dbdc
Comments
Post a Comment