Skip to content

Instantly share code, notes, and snippets.

@ixcoder001
Created December 13, 2020 15:17
Show Gist options
  • Save ixcoder001/3b449e39e857077957444e4c1121dbdc to your computer and use it in GitHub Desktop.
Save ixcoder001/3b449e39e857077957444e4c1121dbdc to your computer and use it in GitHub Desktop.
Higher Order Functions - Swift
/**
HigherOrder Functions
1. Sort
2. Map
3. Reduce
4. Filter
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 neede
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 accept
1. one or more functions as an input (or)
2. returns a value of function type as output (or)
3. doing both
Passing Function
In languages where functions are first-class citizens, functions can be passed as arguments to other functions in the same way as other values.
Returning Function
When returning a function, we are in fact returning its closure. Strictly speaking, simple function without params and return type does still return a value, even though no return value is defined.
Functions without a defined return type return a special value of type Void. This is simply an empty tuple, which is written as (). a function have no params and Void as return type (which means no return type).
So the function type would be mentioned as "() -> Void", where () represents no params and Void represents no return values.
*/
func 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()
}
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 higherOrderFunctionAcceptingFunctionAsParamsOne(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
}
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
///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
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 numberValues = [1, 2, 5, 3, 8]
numberValues.sort()
print(numberValues) // [1, 2, 3, 5, 8]
numberValues.sort(by: >)
print(numberValues) // [8, 5, 3, 2, 1]
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.
Complexity: O(m + n), where n is the length of this sequence and m is the length of the result.
*/
let numbersCompactMapped = numbers.compactMap { Int($0) } // [1, 2, 5, 3]
/**
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 flatMap with a transformation that returns an array
In fact, s.flatMap(transform) is equivalent to Array(s.map(transform).joined()).
Complexity: O(m + n), where n is the length of this sequence and m is the length of the result.
*/
let numbersArray = [1, 2, 3, 4]
let mapped = numbersArray.map { Array(repeating: $0, count: $0) }
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
let flatMapped = numbersArray.flatMap { Array(repeating: $0, count: $0) }
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
///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
Returns the result of combining the elements of the sequence using the given closure.
The value to use as the initial accumulating value. initialResult is passed to nextPartialResult the first time the closure is executed.
A closure that combines an accumulating value and an element of the sequence into a new accumulating value, to be used in the next call of the nextPartialResult closure or returned to the caller.
The final accumulated value. If the sequence has no elements, the result is initialResult.
Use the reduce(_:_:) method to produce a single value from the elements of an entire sequence.
Complexity: O(n), where n is the length of the sequence.
*/
var numbersReduce = [1, 2, 5, 3, 8]
let numbersReduceSum = numbersReduce.reduce(0) { (partialResult, nextValue) in
partialResult + nextValue
}
///Filter:
/**
Returns an array containing, in order, the elements of the sequence that satisfy the given predicate. (instance of Sequence method)
func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]
A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element should be included in the returned array.
An array of the elements that isIncluded allowed.
Complexity: O(n), where n is the length of the sequence.
*/
let names = ["Sunil", "Siri", "Sunil N", "Sunny"]
let shortNames = names.filter { $0.count <= 5 } // ["Sunil", "Siri", "Sunny"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment