preface

As developers, we often have to deal with complex business algorithms (various FOR loops) that take hours or even days. Due to swift’s higher-order functions, such as Map, Reduce, filter, etc., some of the complex algorithms can now be easily solved with just a few lines of code.

In this article, I want to show you four previously difficult algorithms that are now very easy to implement thanks to higher-order functions in Swift.

In this article, I’ll use the following Students array as model objects so you can better understand how these higher-order functions work.

let students = [
    Student(id: "991", name: "Jessica", gender: .female, age: 20),
    Student(id: "992", name: "James", gender: .male, age: 25),
    Student(id: "993", name: "Mary", gender: .female, age: 19),
    Student(id: "994", name: "Edwin", gender: .male, age: 27),
    Student(id: "995", name: "Stacy", gender: .female, age: 18),
    Student(id: "996", name: "Emma", gender: .female, age: 22),
]

enum Gender {
    case male
    case female
}

struct Student {
    let id: String
    let name: String
    let gender: Gender
    let age: Int
}

Copy the code

Count the number of occurrences of array elements

Counting the total number of elements in an array is easy, but what if we want to count the number of occurrences of elements based on some condition? For example, suppose we want to count how many male and female students are in the Students array (Gender property).

We can take advantage of the reduce(into:) function of arrays. Let’s look at the following example code:

let genderCount = students.reduce(into: [Gender: Int]()) { result, student in
    
    guard var count = result[student.gender] else {
        // Set initial value to `result`
        result[student.gender] = 1
        return
    }
    
    // Increase counter by 1
    count += 1
    result[student.gender] = count
}

let femaleCount = genderCount[.female]! // Output: 4
let maleCount = genderCount[.male]!     // Output: 2
Copy the code

What the example code above does is reduce the STUDENTS array to a dictionary ‘ ‘of type [Gender: Int]. In the closure, we accumulate and populate the final dictionary by counting the occurrences of male and female students.

reviewSwift reducefunction

So let’s review reduce, reduce is a function that sets an initial value and returns two result variables, which we call result,currentCase

Result: Generally refers to the sum of the results obtained last time

CurrentCase: Indicates the object to be traversed

For example:

Let prices = [20,30,40] let sum = price. reduce(0) {$0 + $1} print(sum) //90Copy the code

Notice that reduce(0) is the initial value of reduce(0), and our function will return whatever result ok, return the function above, and we want to count how many male and female students are in the array of Students

[Gender: Int]() : is a dictionary with Gender as the Key, Int so we can count the total number of boys and girls by Gender. We print the Log Po genderCount

▿ 2 elements ▿ 0:2 elements - key: SwiftUnitTest. Gender. Getting out - value: 4 ▿ 1:2 elements - the key: SwiftUnitTest.Gender.male - value : 2Copy the code

Gets the sum of a model property in an array

Next, I want to show you how to get the sum of an array in just one line of code. Suppose we want to get the sum of the student ages. To do this, we can reduce(_:_:) using array functions like this:

let sum = students.reduce(0) { result, student in
    return result + student.age
}
Copy the code

As you might have guessed, we can further simplify the sample code above by using abbreviated parameter names:

let sum = students.reduce(0, { $0 + $1.age })
Copy the code

For array element types that support the addition operator (+), we can further simplify it by omitting abbreviated parameter names:

Reduce (0, +) // Output: 9 Let sum2 = [5.5, 10.7, 9.43]. Reduce (0, +) // Output: 44.435 let sum3 = [" a ", "b", "c"]. Reduce (" ", +) / / the Output: "ABC"Copy the code

Reduce is very useful for calculating values and concatenating strings.

Gets some random elements from an array

Fetching random elements from an array used to be a difficult algorithm to implement because we had to deal with all kinds of edge cases.

This is now made much easier with the shuffled() and prefix(_:) functions in the Swift array.

Select 3 students randomly from the students array:

// Randomize all elements within the array let randomized = students.shuffled() // Get the first 3 elements in the array  let selected = randomized.prefix(3) let selected2 = randomized.prefix(13) print(selected) print(selected2)Copy the code

One advantage of this approach is that it does not trigger an index out-of-range exception even if we try to fetch more elements than the total number of elements in the array.

The results of

[SwiftUnitTest.Student(id: "996", name: "Emma", gender: SwiftUnitTest.Gender.female, age: 22), 
SwiftUnitTest.Student(id: "991", name: "Jessica", gender: SwiftUnitTest.Gender.female, age: 20), 
SwiftUnitTest.Student(id: "992", name: "James", gender: SwiftUnitTest.Gender.male, age: 25)]


[SwiftUnitTest.Student(id: "996", name: "Emma", gender: SwiftUnitTest.Gender.female, age: 22), 
SwiftUnitTest.Student(id: "991", name: "Jessica", gender: SwiftUnitTest.Gender.female, age: 20),
SwiftUnitTest.Student(id: "992", name: "James", gender: SwiftUnitTest.Gender.male, age: 25), 
SwiftUnitTest.Student(id: "995", name: "Stacy", gender: SwiftUnitTest.Gender.female, age: 18), 
SwiftUnitTest.Student(id: "993", name: "Mary", gender: SwiftUnitTest.Gender.female, age: 19), 
SwiftUnitTest.Student(id: "994", name: "Edwin", gender: SwiftUnitTest.Gender.male, age: 27)]

Copy the code

We can see that the randomness can end up at the highest number 6, not necessarily at 13

Group array elements by conditions

Suppose we want to group students by the first letter of their student name. Traditionally, we had to manually iterate over each element in a number group and group them accordingly.

struct Student {
    let id: String
    let name: String
    let gender: Gender
    let age: Int
}

Copy the code

Now, with the help of the Dictionary(Grouping :by:) initializer, we can do this without using for-in loops. Here it is:

let groupByFirstLetter = Dictionary(grouping: students) { student in
    return student.name.first!
}

/*
 PrintLog:
 [
    ["J": [SwiftUnitTest.Student(id: "991", name: "Jessica", gender: SwiftUnitTest.Gender.female, age: 20), SwiftUnitTest.Student(id: "992", name: "James", gender: SwiftUnitTest.Gender.male, age: 25)],
    "M": [SwiftUnitTest.Student(id: "993", name: "Mary", gender: SwiftUnitTest.Gender.female, age: 19)], 
    "E": [SwiftUnitTest.Student(id: "994", name: "Edwin", gender: SwiftUnitTest.Gender.male, age: 27), SwiftUnitTest.Student(id: "996", name: "Emma", gender: SwiftUnitTest.Gender.female, age: 22)], 
    "S": [SwiftUnitTest.Student(id: "995", name: "Stacy", gender: SwiftUnitTest.Gender.female, age: 18)]]

 ]
 */
Copy the code

As you can see from the sample code above, the initializer will generate a dictionary of type [KeyType: Student]. KEY = the first letter of each Student’s name,

This is especially useful if we want to group students by standard and display them in a multi-part table view. We can even simplify this further by using shorthand parameter names or keypath syntax in Swift

// Using shorthand argument names
let groupByFirstLetter = Dictionary(grouping: students, by: { $0.name.first! })

// Using key path syntax
let groupByFirstLetter = Dictionary(grouping: students, by: \.name.first!)
Copy the code

conclusion

We’ve looked at four scenarios that use higher-order functions to count the number of occurrences of array elements, get the sum of a model attribute in the array, get some random elements from the array, and group array elements by conditions

All of the examples shown above can definitely be solved by using a traditional for-in loop. However, this requires us to handle various edge cases manually, making it very error prone.

By using higher-order functions, we can greatly reduce the complexity of our code, thus reducing the likelihood of errors. Most importantly, it makes our code easier to maintain. Because this section is quite large, I should also share some later, other high order function use method, or if you have any good use scenario, can also leave a message, we learn from each other, ha ha ha ~ have a good weekend!