Skip to content

Commit e9780d6

Browse files
committed
Finish challenge of chapter 3.
1 parent ceca07b commit e9780d6

File tree

3 files changed

+182
-67
lines changed

3 files changed

+182
-67
lines changed

03-transforming-operators/projects/Starter.playground/Contents.swift

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,14 @@ Notice in the `tryMap` operator
8787
}
8888

8989

90-
example(of: "FlatMap") {
90+
example(
91+
of: "FlatMap",
92+
comment: """
93+
FlatMap operator flatten multiple upstream publishers into single downstream publisher that you can subscribe to it.
94+
So you can have a publisher that emits a value and you want to flatMap the publisher it self into something else, i.e into another publisher.
95+
So imagine you have a publisher of <String, Never> and you want to flatMap into <Int, Never>
96+
or even <String, Never> => <String, Never> but doing different logic like the following example.
97+
""") {
9198
func decode(_ codes: [Int]) -> AnyPublisher<String, Never> {
9299
Just(
93100
codes
@@ -96,7 +103,8 @@ example(of: "FlatMap") {
96103
return String(UnicodeScalar(code) ?? " ")
97104
}
98105
.joined()
99-
).eraseToAnyPublisher()
106+
)
107+
.eraseToAnyPublisher()
100108
}
101109

102110
[128144, 32, 72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 32, 128144]
@@ -107,3 +115,84 @@ example(of: "FlatMap") {
107115
receiveValue: { print($0)})
108116
.store(in: &subscriptions)
109117
}
118+
119+
example(
120+
of: "Flat map 2",
121+
comment:"""
122+
With FlatMap Operator you can chain the upstream operators one after another, and return one publisher which will publish to the down stream.
123+
Each upstream publisher input should be the output from the pervious publisher.
124+
""") {
125+
126+
func oddOrEven(_ numbers: [Int]) -> AnyPublisher<[Bool], Never> {
127+
Just (
128+
numbers.compactMap { $0.isMultiple(of:2) }
129+
).eraseToAnyPublisher()
130+
}
131+
132+
func formatNumbers(_ numbers: [Bool]) -> AnyPublisher<String, Never> {
133+
Just (
134+
numbers
135+
.map { return $0 == true ? "Even" : "Odd" }
136+
.joined(separator: ", ")
137+
).eraseToAnyPublisher()
138+
}
139+
140+
func upperCase(_ string: String) -> AnyPublisher<String, Never> {
141+
Just(
142+
string.uppercased()
143+
).eraseToAnyPublisher()
144+
}
145+
146+
[1, 3, 18, 19, 500]
147+
.publisher
148+
.collect()
149+
.flatMap(oddOrEven)
150+
.flatMap(formatNumbers)
151+
.flatMap(upperCase)
152+
.sink(receiveValue: { print($0) } )
153+
.store(in: &subscriptions)
154+
}
155+
156+
example(of: "replaceNil") {
157+
["A", nil, "B"]
158+
.publisher
159+
.eraseToAnyPublisher()
160+
.replaceNil(with: "-")
161+
.sink(receiveValue: { print($0) } )
162+
.store(in: &subscriptions)
163+
}
164+
165+
example(of: "Empty Publisher",
166+
comment: """
167+
There is new publisher type called Empty which is empty 🤷‍♂️, i.e Publisher that won't send anything
168+
"""
169+
) {
170+
let empty = Empty<Int, Never>()
171+
empty
172+
.sink(receiveCompletion: { print($0) },
173+
receiveValue: { $0 } )
174+
.store(in: &subscriptions)
175+
}
176+
177+
example(of: "Replace Empty") {
178+
let empty = Empty<Int, Never>()
179+
empty
180+
.replaceEmpty(with: 5)
181+
.sink(receiveCompletion: { print($0) },
182+
receiveValue: { print($0) } )
183+
.store(in: &subscriptions)
184+
185+
}
186+
187+
example(of: "Scan") {
188+
var randomGenerator: Int { Int.random(in: -10...10) }
189+
func random(_ number: Int) -> Int { randomGenerator }
190+
let workingDaysValues = (0...25).map(random)
191+
workingDaysValues
192+
.publisher
193+
.scan(50) { current, latest in
194+
max(0, current + latest)
195+
}
196+
.sink { _ in }
197+
.store(in: &subscriptions)
198+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
<LoggerValueHistoryTimelineItem
6+
documentLocation = "file:///Users/ahmadatef/Development/Learning/Combine/03-transforming-operators/projects/Starter.playground#CharacterRangeLen=22&amp;CharacterRangeLoc=6185&amp;EndingColumnNumber=0&amp;EndingLineNumber=187&amp;StartingColumnNumber=0&amp;StartingLineNumber=186&amp;Timestamp=684948385.103197"
7+
selectedRepresentationIndex = "0">
8+
</LoggerValueHistoryTimelineItem>
9+
<LoggerValueHistoryTimelineItem
10+
documentLocation = "file:///Users/ahmadatef/Development/Learning/Combine/03-transforming-operators/projects/Starter.playground#CharacterRangeLen=24&amp;CharacterRangeLoc=6465&amp;EndingColumnNumber=0&amp;EndingLineNumber=194&amp;StartingColumnNumber=13&amp;StartingLineNumber=193&amp;Timestamp=684948385.103282"
11+
selectedRepresentationIndex = "0">
12+
</LoggerValueHistoryTimelineItem>
13+
</TimelineItems>
14+
</Timeline>

03-transforming-operators/projects/challenge/Starter.playground/Contents.swift

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,73 +4,85 @@ import Combine
44
var subscriptions = Set<AnyCancellable>()
55

66
example(of: "Create a phone number lookup") {
7-
let contacts = [
8-
"603-555-1234": "Florent",
9-
"408-555-4321": "Marin",
10-
"217-555-1212": "Scott",
11-
"212-555-3434": "Shai"
12-
]
13-
14-
func convert(phoneNumber: String) -> Int? {
15-
if let number = Int(phoneNumber),
16-
number < 10 {
17-
return number
18-
}
19-
20-
let keyMap: [String: Int] = [
21-
"abc": 2, "def": 3, "ghi": 4,
22-
"jkl": 5, "mno": 6, "pqrs": 7,
23-
"tuv": 8, "wxyz": 9
7+
let contacts = [
8+
"603-555-1234": "Florent",
9+
"408-555-4321": "Marin",
10+
"217-555-1212": "Scott",
11+
"212-555-3434": "Shai"
2412
]
25-
26-
let converted = keyMap
27-
.filter { $0.key.contains(phoneNumber.lowercased()) }
28-
.map { $0.value }
29-
.first
30-
31-
return converted
32-
}
33-
34-
func format(digits: [Int]) -> String {
35-
var phone = digits.map(String.init)
36-
.joined()
37-
38-
phone.insert("-", at: phone.index(
39-
phone.startIndex,
40-
offsetBy: 3)
41-
)
42-
43-
phone.insert("-", at: phone.index(
44-
phone.startIndex,
45-
offsetBy: 7)
46-
)
47-
48-
return phone
49-
}
50-
51-
func dial(phoneNumber: String) -> String {
52-
guard let contact = contacts[phoneNumber] else {
53-
return "Contact not found for \(phoneNumber)"
13+
14+
//4085554321
15+
16+
func convert(phoneNumber: String) -> Int? {
17+
if let number = Int(phoneNumber),
18+
number < 10 {
19+
print("Found")
20+
print(number)
21+
return number
22+
}
23+
24+
let keyMap: [String: Int] = [
25+
"abc": 2, "def": 3, "ghi": 4,
26+
"jkl": 5, "mno": 6, "pqrs": 7,
27+
"tuv": 8, "wxyz": 9
28+
]
29+
30+
let converted = keyMap
31+
.filter { $0.key.contains(phoneNumber.lowercased()) }
32+
.map { $0.value }
33+
.first
34+
print(converted)
35+
return converted
36+
}
37+
38+
func format(digits: [Int]) -> String {
39+
var phone = digits.map(String.init)
40+
.joined()
41+
42+
phone.insert("-", at: phone.index(
43+
phone.startIndex,
44+
offsetBy: 3)
45+
)
46+
47+
phone.insert("-", at: phone.index(
48+
phone.startIndex,
49+
offsetBy: 7)
50+
)
51+
52+
return phone
53+
}
54+
55+
func dial(phoneNumber: String) -> String {
56+
guard let contact = contacts[phoneNumber] else {
57+
return "Contact not found for \(phoneNumber)"
58+
}
59+
60+
return "Dialing \(contact) (\(phoneNumber))..."
61+
}
62+
63+
64+
let input = PassthroughSubject<String, Never>()
65+
66+
input
67+
.map(convert)
68+
.replaceNil(with: 0)
69+
.collect(10)
70+
.map(format)
71+
.map(dial)
72+
.sink(receiveValue: { print($0)})
73+
74+
75+
// "0!1234567".forEach {
76+
// input.send(String($0))
77+
// }
78+
79+
"4085554321".forEach {
80+
input.send(String($0))
81+
}
82+
83+
"A1BJKLDGEH".forEach {
84+
input.send("\($0)")
5485
}
55-
56-
return "Dialing \(contact) (\(phoneNumber))..."
57-
}
58-
59-
let input = PassthroughSubject<String, Never>()
60-
61-
<#Add your code here#>
62-
63-
"0!1234567".forEach {
64-
input.send(String($0))
65-
}
66-
67-
"4085554321".forEach {
68-
input.send(String($0))
69-
}
70-
71-
"A1BJKLDGEH".forEach {
72-
input.send("\($0)")
73-
}
7486
}
7587

7688
/// Copyright (c) 2021 Razeware LLC

0 commit comments

Comments
 (0)