给定Observable<NaturalNumber>
代表所有自然数的序列。
示例1 (在this answer中解决,请查看下一个示例)
如何获得包含范围内所有数字的和表达式和结果的Single<String>
?
例如:10至13的范围 - > “11 + 12 = 23”
到目前为止,这是我所拥有的(并且不喜欢):
let min = 10
let max = 15
//No special meaning, just to add an "error" case
let maxAllowed = 20
Single<String>.create(subscribe: { (complete) -> Disposable in
return Observable.range(start: 0, count: Int.max)
.filter { min < $0 && max > $0 }
.scan([], accumulator: { (acc: [Int], number) in
guard number < maxAllowed else {
complete(.error(SomeError()))
return []
}
return acc + [number]
})
.single { $0.count == (max - min - 1) }
.map { range in
let sum = range.reduce(0, +)
return range.reduce("", { (acc, number) -> String in
if number == (max - 1) {
return acc + " + \(number) = \(sum)"
} else {
return acc + "\(acc != "" ? " + " : "")\(number)"
}
})}
.subscribe(onNext: { complete(.success($0)) })
}).subscribe(onSuccess: { (s) in
print("Success: \(s)") // "Success: 11 + 12 + 13 + 14 = 50"
}, onError: { (e) in
print("Error")
}).disposed(by: d)
示例2
给定struct Point3D
需要从大小为3的数组构造。如何获得输入向量中的值应该在指定范围内的Single<Point3D>
?
let min = 10
let max = 15
//No special meaning, just to add an "error" case
let maxAllowed = 20
struct Point3D {
let x: Int
let y: Int
let z: Int
init(vector: [Int]) {
x = vector[0]
y = vector[1]
z = vector[2]
}
}
Single<Point3D>.create(subscribe: { (complete) -> Disposable in
return Observable.range(start: 0, count: Int.max)
.filter { min < $0 && max > $0 }
.scan([], accumulator: { (acc: [Int], number) in
guard number < maxAllowed else {
complete(.error(SomeError()))
return []
}
return acc + [number]
})
.single { $0.count == 3 }
.map(Point3D.init(vector:))
.subscribe(onNext: { complete(.success($0)) })
}).subscribe(onSuccess: { (s) in
print("Success: \(s)") // "Success: Point3D #1(x: 11, y: 12, z: 13)"
}, onError: { (e) in
print("Error")
}).disposed(by: d)
请记住: 这是我所遇到的一个真正问题的抽象,涉及来自蓝牙连接的无限值序列。所以请尽量避免改变问题而不是解决方案的答案,除非你认为上述情况有意义。
我想要提取的模式是:从无限序列中选择一些值,并构造一个只包含这些值的新值。收集完所有值后,使用.success(allValues)
我想要改进的例子是:
Single<T>.create()
包装器。只有在某些情况下能够完成和出错(示例中的maxAlloed
)。此外,我不确定asSingle()
运算符是否在返回值(?)后完成返回的Single
。filter
,scan
和single
从原始序列中获取值并控制有限序列应何时完成。想一想示例2 。由于
答案 0 :(得分:0)
如果我已正确理解问题(将无限序列的连续部分缩减为Single
),我将撰写以下内容:
在用于求和的代码中(但对于任何无限序列,即使是蓝牙事件也应该如此):
let sum = Observable.range(start: 0, count: Int.max)
.skipWhile({ $0 <= min })
.takeWhile({ $0 < max })
.reduce(0, accumulator: +)
.asSingle()
// Can't have any errors in the above code, but to demonstrate the general case
sum.subscribe(onSuccess: { print($0) },
onError: { (e) in print("Error: \(e)") })
.disposed(by: d)
我不太清楚maxAllowed
在原始代码中做了什么(这可能是复杂性),但如果值超出范围则抛出错误,那么你只是扔进reduce
累加器。或者您可以在中间添加一个标识map
,只查找无效值并在这些情况下抛出错误。