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
reduce
function
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!