Github.com/agelessman/…
In a broad sense, there are only three mathematical operations we want for a pipline. To find the maximum, minimum or number in the data set, we can use other Operators for more subtle and precise control.
max
.max() will wait for the upstream publisher to send the.finished event and send the maximum value in the data stream. All problems involving calculating extreme values must implement the Comparable protocol because only this protocol can be used to compare the sizes of two values.
_ = [1.2.3.4]
.publisher
.max()
.sink(receiveCompletion: { completion in
.
}, receiveValue: { someValue in
print("someValue: \(someValue)")})Copy the code
However, in a real development environment, where data flows are likely to be of a variety of types and not all of the data implements the Comparable protocol, what should we do?
For example:
struct Student {
let age: Int
let name: String
}
let students = [Student(age: 15, name: "Zhang"),
Student(age: 16, name: "Bill"),
Student(age: 17, name: "Fifty")]
Copy the code
Student does not implement the Comparable protocol. Instead, Max provides an additional argument, which is a closure that can be passed in a custom sorting strategy. Its definition is as follows:
public func max(by areInIncreasingOrder: (Publishers.Sequence<Elements.Failure>.Output.Publishers.Sequence<Elements.Failure>.Output) - >Bool) -> Optional<Publishers.Sequence<Elements.Failure>.Output>.Publisher
Copy the code
The point is that areInIncreasingOrder, which requires closure results to adhere to the concept of ascending order, so the code looks like this:
.max { v1, v2 -> Bool in
v1.age < v2.age
}
Copy the code
The complete code is as follows:
_ = students
.publisher
.max { v1, v2 -> Bool in
v1.age < v2.age
}
.sink(receiveCompletion: { completion in
.
}, receiveValue: { someValue in
print("someValue: \(someValue)")})Copy the code
Schematic diagram:
In Combine, any Operator that uses closures is likely to throw an exception, and Max is no exception. For example, if we find a student whose age==0, we throw an exception like this:
enum MyCustomError: Error {
case customError
}
let students1 = [Student(age: 15, name: "Zhang"),
Student(age: 16, name: "Bill"),
Student(age: 0, name: "Fifty")]
_ = students1
.publisher
.tryMax { v1, v2 -> Bool in
if v1.age = = 0 || v2.age = = 0 {
throw MyCustomError.customError
}
return v1.age < v2.age
}
.sink(receiveCompletion: { completion in
print("It's over.")
switch completion {
case .finished:
print("Complete")
case .failure(let error):
print("Error:\(error.localizedDescription)")
}
}, receiveValue: { someValue in
print("someValue: \(someValue)")})Copy the code
Once an exception is thrown, the pipline will end and Sink will receive the. Failure event. The schematic diagram is as follows:
min
Min is the opposite of Max, and is used to calculate the minimum value in the data stream, which we won’t explain further. The code is as follows:
.min()
Copy the code
struct Student {
let age: Int
let name: String
}
let students = [Student(age: 15, name: "Zhang"),
Student(age: 16, name: "Bill"),
Student(age: 17, name: "Fifty")]
.min { v1, v2 -> Bool in
v1.age < v2.age
}
Copy the code
.tryMin { v1, v2 -> Bool in
if v1.age = = 0 || v2.age = = 0 {
throw MyCustomError.customError
}
return v1.age < v2.age
}
Copy the code
count
The count is understandable because it waits for the upstream publisher to send the. Finished event and returns the number of data. In some scenarios, this Operator is used when we need to count the number of data so that we don’t need to store the data in an array and count it.
.count()
Copy the code