Skip to content

Commit 17f54cd

Browse files
author
Bob Lee
committed
Finished doc for filter
1 parent b2ded8e commit 17f54cd

File tree

6 files changed

+71
-21
lines changed

6 files changed

+71
-21
lines changed

course/functional-programming/filter.md

+65-19
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ How to get things done with one line of code?
88
> **Note:** Most people use Swift functions without knowing the behind implementation
99
1010
### Imperative/Non-functional
11+
Let's attempt to grab even numbers using a non-functional approach.
12+
1113
```swift
1214
// Get even numbers
1315
var evens = [Int]()
@@ -19,16 +21,20 @@ for i in 1...10 {
1921
}
2022
```
2123

24+
It certainly works. But, you know what I'm about to say.
25+
2226
### Declarative/Functional
23-
You may execute the task above using the built-in `filter` method by the `Array` struct. However, you will discover how things work throughout this lesson. If you are stuck, don't you worry. I will walk you through.
27+
If you remember correct, `Array` is just a `struct` and it contains built-in methods. `filter` is one of them. Let us utilize the `filter` function to get things done. You don't have to understand what goes under the hood at this point, but you will by creating our own custom `filter` function.
2428

2529
```swift
2630
Array(1...10).filter { (number) in number % 2 == 0 }
2731
Array(1...10).filter { $0 % 2 == 0 }
2832
```
2933

34+
Let us find out what the heck is going on. Don't you worry. As long as you are comfortable with closures and generics, you will get through with me.
35+
3036
### Become an A Student
31-
My mom used to like when I handed my grade sheet filled with "A"s. Let's find out how to only get "A" letters to please my mom.
37+
My mom used to love (still do since I'm in college) when I handed my grade sheet filled with "A"s. Let's find out how to only get "A" letters to please my mom.
3238

3339
```swift
3440
let recentGrade = ["A", "A", "A", "A", "B", "D"] // It can be any data
@@ -56,6 +62,7 @@ The code above tells you the steps how you filtered `recentGrade`. This is long,
5662
From now on, you might find it difficult. Bear with me. First of all, let's create a function either returns `true` or `false` based on the parameter.
5763

5864
Create closure block that returns true/false
65+
5966
```swift
6067
var isMomHappy: (String) -> Bool = { grade in return grade == "A" }
6168
isMomHappy = { $0 == "A" }
@@ -64,6 +71,8 @@ isMomHappy("A") // true
6471
isMomHappy("B") // true
6572
```
6673

74+
Create a function that take the closure block whose type is `(String) -> Bool`. I will call the parameter as `operation`.
75+
6776
```swift
6877
func simpleStringFilter(grades: [String], operation: (String) -> Bool) {
6978
var happyGrade: [String] = []
@@ -75,6 +84,16 @@ func simpleStringFilter(grades: [String], operation: (String) -> Bool) {
7584
}
7685
```
7786

87+
Within the `simpleStringFilter`, the `operation` closure is executed. If `operation` returns `true`, append the grade to `happyGrade`.
88+
89+
Let's execute `simpleStringFilter`. The `isMomHappy` closure is passed to the `operation` parameter.
90+
91+
```swift
92+
simpleStringFilter(grades: recentGrade, operation: isMomHappy) // ["A", ...]
93+
```
94+
95+
The entire function may also return `[String]`
96+
7897
```swift
7998
func stringFilter(grades: [String], operation: (String) -> Bool) -> [String] {
8099
var happyGrade: [String] = []
@@ -87,55 +106,76 @@ func stringFilter(grades: [String], operation: (String) -> Bool) -> [String] {
87106
}
88107
```
89108

90-
### Generic Filter
109+
Execute `stringFilter`.
110+
111+
```swift
112+
let myGrade = ["A", "A", "A", "A", "B", "D"]
113+
let happyGrade = stringFilter(grades: myGrade, operation: isMomHappy)
114+
happyGrade // ["A", ...]
115+
```
116+
117+
### Pass Closure Directly
118+
So far, you've passed the closure block indirectly to the `operation` parameter using `isMomHappy`. However, you may directly enter a closure block. The syntax may look strange but I'm sure you are comfortable with closures at this point.
119+
91120
```swift
92-
func bobFilter<Bob>(array: [Bob], logic: (Bob) -> Bool) -> [Bob] {
121+
stringFilter(grades: myGrade, operation: { element in return element == "A" })
122+
stringFilter(grades: myGrade, operation: { $0 == "A" })
123+
```
124+
125+
### Generic Function
126+
If you remember from Chapter 1, intro to generics, it doesn't make sense to create a distinct function just for `String` only. Let us utilize the Swift generics.
127+
128+
```swift
129+
func bobFilter<Bob>(array: [Bob], operation: (Bob) -> Bool) -> [Bob] {
93130
var result: [Bob] = []
94131
for element in array {
95-
if logic(element) {
132+
if operation(element) {
96133
result.append(element)
97134
}
98135
}
99136
return result
100137
}
101138
```
102139

140+
The placeholder type of `bobFilter` is `Bob` which should be defined later. Usually, we use `T` instead.
141+
103142
```swift
104-
func myFilter<T>(array: [T], logic: (T) -> Bool) -> [T] {
143+
func myFilter<T>(array: [T], operation: (T) -> Bool) -> [T] {
105144
var result: [T] = []
106145
for element in array {
107-
if logic(element) {
146+
if operation(element) {
108147
result.append(element)
109148
}
110149
}
111150
return result
112151
}
113152
```
114153

115-
```swift
116-
let myGrade = ["A", "A", "A", "A", "B", "D"]
117-
let lovelyGrade = stringFilter(grades: myGrade, operation: isMomHappy)
118-
```
119-
120-
```swift
121-
stringFilter(grades: myGrade, operation: { $0 == "A" })
122-
```
154+
### Examples
155+
So, let us find out how `myFilter` can be used.
123156

157+
#### Ex 1) Filter Numbers
124158
```swift
125-
let AStudent = myFilter(array: Array(1...100), logic: { $0 >= 93 && $0 <= 100 })
159+
let AStudent = myFilter(array: Array(1...100), operation: { $0 >= 93 && $0 <= 100 })
126160
print(AStudent) // [93, 94, 95, ... 100]
127161
```
128162

163+
#### Ex 2) Vote Counting
129164
```swift
130165
let answer = [true, false, true, false, false, false, false]
131-
let trueAnswer = myFilter(array: answer, logic: { $0 == true })
166+
let trueAnswer = myFilter(array: answer, operation: { $0 == true })
132167
```
133168

169+
The rest is history. You can use your imagination from now on.
170+
171+
You may also utilize trailing closures to beautify.
172+
134173
```swift
135-
// Trailing Closure
136174
let falseAnswer = myFilter(array: answer) { $0 == false }
137175
```
138176

177+
### Built-in Swift Filter
178+
As I mentioned earlier, `Array<T>` comes with its own `filter`. Let us utilize. We don't have to reinvent.
139179

140180
```swift
141181
let zeroToHund = Array(1...100)
@@ -144,6 +184,7 @@ zeroToHund.filter{ $0 % 2 == 0 }.filter { $0 <= 50 }
144184
```
145185

146186
### The Purest Form
187+
The built-in `filter` may look something like this. Since you have not taken generics protocols in the following chapter and Advanced Swift, you may be confused with `Element`. It's the type of an array for now.
147188

148189
```swift
149190
extension Array {
@@ -159,14 +200,19 @@ extension Array {
159200
}
160201
```
161202

162-
Test it out.
203+
Let us test it out.
163204

164205
```swift
165206
let result = Array(1...100).myFilter { $0 % 2 == 0 }
166207
```
167208

168209
### Source Code
210+
[6002_filter.playground]()
169211

170212
### Resources
213+
[Intro to Functional Programming](https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13)
171214

172215
## Conclusion
216+
Congratulations. You've learned what goes under the hood of `filter`, one of the most common functions. From now on, you understand what it means to pass a closure block at the end and you've learned how the closure block is used within the main function. This principle applies in every other major functions we will take a look at. Along with generics, it allows reusability, thus scalability in your code base.
217+
218+
At the end of the lesson, I've mentioned `Element` of an array. I don't expect you to know what it is. However, in the last chapter of this course, you will learn the behind scene by understanding the statement, "Swift is a protocol oriented programming language". Let's continue.

course/functional-programming/intro-functional-paradigm.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,4 @@ A functional paradigm ensures no mutability or no change in state when used.
9797
## Conclusion
9898
Now, I've demystified the concept of "Functional Programming" for you. Again, based on my simplest definition, it's nothing more than using functions to solve problems.
9999

100-
In the Swift Foundation library built by Apple Engineers there are dozens of useful functions for us developers may use. However, as a developer, we've got to know the behind scene of each function. In the rest of the chapter, you will learn how those functions are created and you will be able to produce on your custom functions depending on your need. From now on, the lesson can get rough and tough, again, make sure you completely understand closures and generics before you jump in.
100+
In the Swift Foundation library built by Apple Engineers, there are dozens of useful functions for us developers may use. However, as a developer, we've got to know the behind scene of each function. In the rest of the chapter, you will learn how those functions are created and you will be able to produce on your custom functions depending on your need. From now on, the lesson can get rough and tough, again, make sure you completely understand closures and generics before you jump in.
Binary file not shown.

source-code/6000_functional_programming/6002_filter.playground/Contents.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ func simpleStringFilter(grades: [String], operation: (String) -> Bool) {
5757
}
5858
}
5959

60+
//: Execute the function by passing `isMomHappy`
61+
simpleStringFilter(grades: recentGrade, operation: isMomHappy) // ["A", ...]
62+
63+
6064
func stringFilter(grades: [String], operation: (String) -> Bool) -> [String] {
6165
var happyGrade: [String] = []
6266
for grade in grades {
@@ -67,8 +71,8 @@ func stringFilter(grades: [String], operation: (String) -> Bool) -> [String] {
6771
return happyGrade
6872
}
6973

70-
7174
let myGrade = ["A", "A", "A", "A", "B", "D"]
75+
stringFilter(grades: myGrade, operation: isMomHappy)
7276

7377
//: Pass the closure block indirectly
7478
let lovelyGrade = stringFilter(grades: myGrade, operation: isMomHappy)

0 commit comments

Comments
 (0)