Skip to content
  • Home
  • About us
  • Contact
  • Privacy Policy
  • Disclaimer
  • Swift Online Compiler
iOS Interview Questions and Tutorials

iOS Interview Questions and Tutorials

Higher-Order Functions in Swift: Brief Explanation with Code Examples

Posted on July 7, 2024July 8, 2024 By Sid No Comments on Higher-Order Functions in Swift: Brief Explanation with Code Examples

Table of Contents

Toggle
  • What is Higher-Order Functions in Swift ?
    • Common Higher-Order Functions in Swift
      • map
      • filter
      • reduce
      • compactMap
      • Custom Higher-Order Functions
      • Custom implementation of higher-order functions in Swift
        • Custom Implementation of map
        • Custom Implementation of filter
      • Custom Implementation of reduce
      • Custom Implementation of compactMap
    • Conclusion

What is Higher-Order Functions in Swift ?

Higher-order functions in Swift are functions that take other functions as arguments or return functions as their results.

They are powerful tools in functional programming and can help make your code more expressive and concise.

Common Higher-Order Functions in Swift

map

In Swift, the map function transforms each element in a collection using a specified closure and returns a new collection containing the transformed elements.

How Map Works:

The map function takes a closure as its argument. This closure defines how to transform each element in the original collection. The closure takes an element of the original collection as its parameter and returns the transformed element. The map function then applies this closure to each element in the collection and returns a new collection containing the results.

Syntax

Here is the basic syntax for using the map function:

let newCollection = oldCollection.map { element in
    // Transformation code
    return transformedElement
}

Example 1: Simple Transformation

Let’s start with a simple example where we want to transform an array of integers by squaring each element.

let numbers = [1, 2, 3, 4, 5]
let squares = numbers.map { $0 * $0 }
print(squares)  // Output: [1, 4, 9, 16, 25]

In this example:

  • numbers is the original array.
  • The closure { $0 * $0 } takes each element ($0) and returns its square.
  • map applies this closure to each element in numbers and returns a new array, squares, containing the squared values.

Example 2: Transforming Strings

You can also use map to transform arrays of strings. For instance, converting an array of strings to their uppercase equivalents:

let lowercaseStrings = ["apple", "banana", "cherry"]
let uppercaseStrings = lowercaseStrings.map { $0.uppercased() }
print(uppercaseStrings)  // Output: ["APPLE", "BANANA", "CHERRY"]

In this example:

  • lowercaseStrings is the original array of strings.
  • The closure { $0.uppercased() } converts each string to uppercase.
  • map applies this closure to each element in lowercaseStrings and returns a new array, uppercaseStrings, containing the uppercase strings.

Example 3: Complex Transformation

You can perform more complex transformations, such as converting an array of dictionaries to an array of custom objects.

struct Person {
    let name: String
    let age: Int
}

let peopleDicts = [
    ["name": "Alice", "age": 25],
    ["name": "Bob", "age": 30],
    ["name": "Charlie", "age": 35]
]

let people = peopleDicts.map { dict in
    Person(name: dict["name"] as! String, age: dict["age"] as! Int)
}

print(people)

// Output: [Person(name: "Alice", age: 25), Person(name: "Bob", age: 30), Person(name: "Charlie", age: 35)]

In this example:

  • peopleDicts is an array of dictionaries, where each dictionary represents a person.
  • The closure converts each dictionary into a Person object by extracting the name and age values and using them to initialize a Person instance.
  • map applies this closure to each dictionary in peopleDicts and returns a new array, people, containing the Person objects.
filter

The filter function in Swift allows you to create a new collection containing only the elements of an original collection that satisfy a given condition (predicate).

How filter Works

The filter function takes a closure that returns a Boolean value. This closure is applied to each element of the collection, and only those elements for which the closure returns true are included in the new collection.

Syntax

Here is the basic syntax for using the filter function:

let newCollection = oldCollection.filter { element in
    // Condition that returns a Boolean
    return condition
}

Example 1: Filtering Even Numbers

Let’s start with a simple example where we want to filter an array of integers to include only the even numbers.

let numbers = [1, 2, 3, 4, 5]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers)  // Output: [2, 4]

In this example:

  • numbers is the original array.
  • The closure { $0 % 2 == 0 } checks if each element ($0) is even.
  • filter applies this closure to each element in numbers and returns a new array, evenNumbers, containing only the even numbers.

Example 2: Filtering Strings

You can also use filter to work with arrays of strings. For instance, filtering an array of strings to include only those that contain a specific substring:

let fruits = ["apple", "banana", "cherry", "date"]
let fruitsWithA = fruits.filter { $0.contains("a") }
print(fruitsWithA)  // Output: ["apple", "banana", "date"]

In this example:

  • fruits is the original array of strings.
  • The closure { $0.contains("a") } checks if each string contains the letter “a”.
  • filter applies this closure to each string in fruits and returns a new array, fruitsWithA, containing only the strings that include “a”.

Example 3: Filtering Custom Objects

You can also use filter with custom objects. For example, filtering an array of custom Person objects to include only those above a certain age.

struct Person {
    let name: String
    let age: Int
}

let people = [
    Person(name: "Alice", age: 25),
    Person(name: "Bob", age: 30),
    Person(name: "Charlie", age: 35)
]

let adults = people.filter { $0.age >= 30 }
print(adults)  // Output: [Person(name: "Bob", age: 30), Person(name: "Charlie", age: 35)]

In this example:

  • people is the original array of Person objects.
  • The closure { $0.age >= 30 } checks if each person’s age is 30 or above.
  • filter applies this closure to each Person object in people and returns a new array, adults, containing only the people who are 30 or older.
reduce

The reduce function in Swift is a powerful higher-order function that allows you to combine all elements of a collection into a single value using a given closure.

This is done by applying a closure that specifies how to combine the elements.

How reduce Works

The reduce function takes two arguments:

  1. An initial value.
  2. A closure that combines the current accumulated value with each element of the collection.

The closure is applied sequentially to each element of the collection, along with the accumulated value, to produce a single result.

Syntax

Here is the basic syntax for using the reduce function:

let result = collection.reduce(initialValue) { accumulator, element in
    // Combine accumulator and element
    return newAccumulator
}

Example 1: Calculating the Product of Numbers

You can use reduce to calculate the product of all elements in an array of integers.

let numbers = [1, 2, 3, 4, 5]
let product = numbers.reduce(1) { $0 * $1 }
print(product)  // Output: 120

In this example:

  • numbers is the original array.
  • 1 is the initial value for the product.
  • The closure { $0 * $1 } multiplies each element ($1) by the current accumulated product ($0).
  • reduce applies this closure to each element in numbers and returns the total product, which is 120.

Detailed Explanation

  1. Array Definition:
let numbers = [1, 2, 3, 4, 5]

This line defines an array of integers named numbers containing the values [1, 2, 3, 4, 5].

2. Using reduce Without Shorthand i.e ($0,$1) to understand better:

let product = numbers.reduce(1, { (accumulator: Int, element: Int) -> Int in
    return accumulator * element
})

This line uses the reduce function to calculate the product of all elements in the numbers array. Let’s break it down:

  • Initial Value: 1The first argument to reduce is the initial value for the accumulator. In this case, the initial value is 1, which is the neutral element for multiplication (multiplying by 1 doesn’t change the product).
  • Closure Definition:
{ (accumulator: Int, element: Int) -> Int in
    return accumulator * element
}

The second argument to reduce is a closure that defines how to combine the elements of the array. This closure has two parameters:

  • accumulator: The current accumulated value, which starts with the initial value 1.
  • element: The current element from the array being processed.

The closure multiplies the accumulator by the element and returns the result, which becomes the new accumulator value for the next iteration.

3. Iterative Process:

The reduce function processes each element in the array as follows:

    • Initial State:
      • accumulator = 1 (initial value)
    • First Iteration:
      • element = 1
      • accumulator = 1 * 1 = 1
    • Second Iteration:
      • element = 2
      • accumulator = 1 * 2 = 2
    • Third Iteration:
      • element = 3
      • accumulator = 2 * 3 = 6
    • Fourth Iteration:
      • element = 4
      • accumulator = 6 * 4 = 24
    • Fifth Iteration:
      • element = 5
      • accumulator = 24 * 5 = 120

4. Final Result:

After processing all elements, the final value of accumulator is 120, which is the product of all elements in the numbers array.

5. Print the Result:

print(product) // Output: 120

This line prints the result, which is 120.

Example 2: Summing Numbers

Let’s start with a simple example where we want to sum all the elements in an array of integers.

let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce(0) { $0 + $1 }
print(sum)  // Output: 15

In this example:

  • numbers is the original array.
  • 0 is the initial value for the sum.
  • The closure { $0 + $1 } adds each element ($1) to the current accumulated sum ($0).
  • reduce applies this closure to each element in numbers and returns the total sum, which is 15.

Example 3: Concatenating Strings

You can also use reduce to concatenate an array of strings.

let words = ["Hello", "world", "from", "Swift"]
let sentence = words.reduce("") { $0 + " " + $1 }
print(sentence)  // Output: " Hello world from Swift"

In this example:

  • words is the original array of strings.
  • "" (an empty string) is the initial value for the concatenated result.
  • The closure { $0 + " " + $1 } concatenates each string ($1) to the current accumulated string ($0), with a space in between.
  • reduce applies this closure to each string in words and returns the concatenated result, which is " Hello world from Swift".

Example 4: Combining Custom Objects

You can also use reduce with custom objects. For instance, calculating the total age of a group of people.

struct Person {
    let name: String
    let age: Int
}

let people = [
    Person(name: "Alice", age: 25),
    Person(name: "Bob", age: 30),
    Person(name: "Charlie", age: 35)
]

let totalAge = people.reduce(0) { $0 + $1.age }
print(totalAge)  // Output: 90

In this example:

  • people is the original array of Person objects.
  • 0 is the initial value for the total age.
  • The closure { $0 + $1.age } adds the age of each Person ($1.age) to the current accumulated total age ($0).
  • reduce applies this closure to each Person in people and returns the total age, which is 90.
compactMap

The compactMap function in Swift is a higher-order function that transforms each element of a collection using a given closure and removes any resulting nil values.

This function is particularly useful for handling collections of optional values and filtering out nil results after a transformation.

How compactMap Works

The compactMap function applies a closure to each element in the collection. This closure returns an optional value. If the closure returns nil for an element, that element is excluded from the resulting collection. Otherwise, the non-nil results are included in the new collection.

Syntax

Here is the basic syntax for using the compactMap function:

let newCollection = oldCollection.compactMap { element in
    // Transformation code that returns an optional value
    return transformedElement
}

Example 1: Filtering and Unwrapping Optionals

Let’s start with a simple example where we have an array of optional integers, and we want to create a new array with only the non-nil values.

let numbers: [Int?] = [1, 2, nil, 4, nil, 6]
let nonNilNumbers = numbers.compactMap { $0 }
print(nonNilNumbers)  // Output: [1, 2, 4, 6]

In this example:

  • numbers is the original array containing optional integers.
  • The closure { $0 } returns each element as it is.
  • compactMap removes any nil values and unwraps the non-nil values, resulting in a new array, nonNilNumbers.

Example 2: Transforming and Filtering Strings

You can also use compactMap to transform and filter strings. For instance, converting an array of strings to integers and filtering out non-numeric strings.

let strings = ["1", "2", "three", "4", "five"]
let numbers = strings.compactMap { Int($0) }
print(numbers)  // Output: [1, 2, 4]

In this example:

  • strings is the original array of strings.
  • The closure Int($0) attempts to convert each string to an integer, returning an optional integer.
  • compactMap removes any nil values (strings that couldn’t be converted to integers) and returns a new array, numbers, containing only the successfully converted integers.

Example 3: Combining Custom Objects

You can use compactMap with custom objects to transform and filter based on specific conditions.

struct Person {
    let name: String
    let age: Int?

}

let people = [
    Person(name: "Alice", age: 25),
    Person(name: "Bob", age: nil),
    Person(name: "Charlie", age: 30)
]

let ages = people.compactMap { $0.age }
print(ages)  // Output: [25, 30]

In this example:

  • people is an array of Person objects, some of which have nil for the age property.
  • The closure { $0.age } returns the age of each person, which is an optional integer.
  • compactMap removes any nil values and returns a new array, ages, containing only the non-nil ages.
Custom Higher-Order Functions

You can also create your own higher-order functions. Here’s an example of a function that takes another function as an argument:

func applyTwice(_ function: (Int) -> Int, to value: Int) -> Int {
    return function(function(value))
}

let result = applyTwice({ $0 * 2 }, to: 3)
print(result)  // Output: 12

In this example, the applyTwice function takes a function that transforms an Int and an Int value, applies the function to the value twice, and returns the result.

Custom implementation of higher-order functions in Swift

I will demonstrate custom implementations of the map, filter, reduce, flatMap, and compactMap higher-order functions in Swift. These implementations will help you understand how these functions work under the hood.

Custom Implementation of map

The map function applies a given transformation to each element of a collection and returns a new collection containing the transformed elements.

extension Array {
    func customMap<T>(_ transform: (Element) -> T) -> [T] {
        var newCollection: [T] = []
        for element in self {
            newCollection.append(transform(element))
        }
        return newCollection
    }
}

// Example usage:
let numbers = [1, 2, 3, 4, 5]
let squares = numbers.customMap { $0 * $0 }
print(squares)  // Output: [1, 4, 9, 16, 25]
Custom Implementation of filter

The filter function returns a new collection containing only the elements that satisfy a given predicate.

extension Array {
    func customFilter(_ predicate: (Element) -> Bool) -> [Element] {
        var result: [Element] = []
        for element in self {
            if predicate(element) {
                result.append(element)
            }
        }
        return result
    }
}

// Example usage:
let numbers = [1, 2, 3, 4, 5]
let evenNumbers = numbers.customFilter { $0 % 2 == 0 }
print(evenNumbers)  // Output: [2, 4]
Custom Implementation of reduce

The reduce function combines all elements of a collection into a single value by applying a closure that specifies how to combine the elements.

extension Array {
    func customReduce<T>(_ initialValue: T, _ combine: (T, Element) -> T) -> T {
        var result = initialValue
        for element in self {
            result = combine(result, element)
        }
        return result
    }
}

// Example usage:
let numbers = [1, 2, 3, 4, 5]
let sum = numbers.customReduce(0) { $0 + $1 }
print(sum)  // Output: 15
Custom Implementation of compactMap

The compactMap function transforms each element in a collection and removes any resulting nil values.

extension Array {
    func customCompactMap<T>(_ transform: (Element) -> T?) -> [T] {
        var result: [T] = []
        for element in self {
            if let value = transform(element) {
                result.append(value)
            }
        }
        return result
    }
}

//Example usage:
let numbers: [Int?] = [1, 2, nil, 4, nil, 6]

let nonNilNumbers1 = numbers.customCompactMap { $0 } // Shorthand

//OR

let nonNilNumbers2:[Int] = numbers.customCompactMap { item in
    guard let unwrappedItem = item else { return nil }
    return unwrappedItem
}

print(nonNilNumbers1) // Output: [1, 2, 4, 6]
print(nonNilNumbers2) // Output: [1, 2, 4, 6]

Conclusion

Higher-order functions are a powerful feature in Swift that can make your code more expressive and concise. By understanding and utilizing functions like map, filter, reduce, flatMap, and custom higher-order functions, you can write more functional and elegant Swift code.

 Read More:

Filter

Top iOS Interview Questions and Answers

Blog

Post navigation

Previous Post: Mutability in Structs and Classes in Swift
Next Post: Enums in Swift: Brief Explanation with Code Examples

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Most Asked iOS Interview Questions

  • Top iOS Interview Questions and Answers

Categories

  • Associated Types(7)
  • Blog
  • Dictionary in Swift(20)
  • Initializers
  • Property Wrapper
  • Singleton in Swift
  • User Defaults(4)
  • XCode 15 Errors

Recent Comments

  1. Sid on Cycle inside MyApp; building could produce unreliable results
  2. Anominous on Cycle inside MyApp; building could produce unreliable results
  3. Aisha on @objc Attribute in Swift

Recent Posts

  • Enums in Swift: Brief Explanation with Code Examples
  • Higher-Order Functions in Swift: Brief Explanation with Code Examples
  • Mutability in Structs and Classes in Swift
  • Delegate Pattern in Swift
  • resueIdentifier in Swift

DSA in Swift

  • 2D Array in Swift: Interview Questions

Copyright © 2025 iOS Interview Questions and Tutorials.

Powered by PressBook WordPress theme