Custom Higher-Order
Part of the Logic & Flow section of Coddy's Swift journey — lesson 42 of 56.
Now you can write your own higher-order functions and they'll fit right in alongside map and filter. The shape is always the same: take a closure parameter, call it inside the loop, return the result.
extension Array {
func myMap<T>(_ transform: (Element) -> T) -> [T] {
var result: [T] = []
for item in self {
result.append(transform(item))
}
return result
}
}
[1, 2, 3].myMap { $0 * 10 } // [10, 20, 30]If extensions feel like a lot, write a free function instead, the idea is the same:
func count<T>(_ items: [T], where predicate: (T) -> Bool) -> Int {
var n = 0
for item in items where predicate(item) {
n += 1
}
return n
}Once you can pass closures around, the standard library stops looking like magic and starts looking like a set of patterns you could write yourself.
Challenge
MediumWrite a free function partition(_ items: [Int], by predicate: (Int) -> Bool) -> ([Int], [Int]) that walks the array once and returns a tuple (matched, rest): elements that satisfied the predicate, and the rest, both in original order.
Read two lines: an integer min, then a comma-separated list of integers. Use your partition with a predicate that checks n > min. Print:
matched: <...>rest: <...>
Each list joined with , (or empty when there's nothing to print).
For input 5 / 2,7,3,8,5, the output is:
matched: 7,8
rest: 2,3,5Cheat sheet
Higher-order functions follow a consistent pattern: accept a closure, call it in a loop, return the result.
As an extension:
extension Array {
func myMap<T>(_ transform: (Element) -> T) -> [T] {
var result: [T] = []
for item in self {
result.append(transform(item))
}
return result
}
}
[1, 2, 3].myMap { $0 * 10 } // [10, 20, 30]As a free function:
func count<T>(_ items: [T], where predicate: (T) -> Bool) -> Int {
var n = 0
for item in items where predicate(item) {
n += 1
}
return n
}A partition function returning a tuple of matched and unmatched elements:
func partition(_ items: [Int], by predicate: (Int) -> Bool) -> ([Int], [Int]) {
var matched: [Int] = []
var rest: [Int] = []
for item in items {
if predicate(item) { matched.append(item) }
else { rest.append(item) }
}
return (matched, rest)
}Try it yourself
let min = Int(readLine()!)!
let nums = readLine()!.components(separatedBy: ",").map { Int($0)! }
// TODO: partition(_:by:) -> ([Int], [Int]); print matched and rest
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Logic & Flow
1Strings In Depth
Count and IndicesCase and TrimSearching in StringsSplitting and JoiningReplacing SubstringsRecap - Username Check8Closures
Closure BasicsTrailing ClosuresCapturing ValuesReturning ClosuresCustom Higher-OrderRecap - Pipeline Builder