可观察的当前值和先前值
Observable Current and Previous Value
我有一个变量,它是一个枚举值数组。这些值随时间变化。
enum Option {
case One
case Two
case Three
}
let options = Variable<[Option]>([ .One, .Two, .Three ])
然后我观察这个变量的变化。问题是,我需要知道最新值和先前值之间的差异。我目前正在这样做:
let previousOptions: [Option] = [ .One, .Two, .Three ]
...
options
.asObservable()
.subscribeNext { [unowned self] opts in
// Do some work diff'ing previousOptions and opt
// ....
self.previousOptions = opts
}
RxSwift 中是否有内置的东西可以更好地管理它?有没有办法始终从信号中获取先前值和当前值?
好了
options.asObservable()
.scan( [ [],[] ] ) { seed, newValue in
return [ seed[1], newValue ]
}
// optional, working with tuple of array is better than array of array
.map { array in (array[0], array[1]) }
//optional, in case you dont want empty array
.skipWhile { [=10=].count == 0 && .count == 0 }
它会 return Observable<([Options], [Options])>
:)
正如 Pham Hoan 所说,scan(_)
是完成这项工作的正确工具。 Marin Todorov 就此写了一篇 good post。
这是我根据 Marin 的 post 得出的结论:
options
.asObservable()
.scan([]) {
(previous, current) in
return Array(previous + [current]).suffix(2)
}
.subscribeNext {
(lastTwoOptions) in
let previousOptions = lastTwoOptions.first
let currentOptions = lastTwoOptions.last
// Do your thing. Remember to check for nil the first time around!
}
.addDisposableTo(self.disposeBag)
希望对您有所帮助
这是一个方便的通用扩展,应该涵盖这些 "I want the previous and the current value" 用例:
extension ObservableType {
func withPrevious(startWith first: E) -> Observable<(E, E)> {
return scan((first, first)) { ([=10=].1, ) }.skip(1)
}
}
我建议这样(对于未来的访问者):
options.asObservable()
.map { (old: [], new: [=10=]) } // change type from array to tuple
.scan((old: [], new: [])) { previous, current in
// seed with an empty tuple & return both information
return (old: previous.new, new: current.new)
}
.subscribe(onNext: { option in
let oldArray = option.old // old
let newArray = option.new // new
}
.addDisposableTo(disposeBag)
一行中的最佳解决方案:
Observable.zip(options, options.skip(1))
.pairwise()
运算符完全可以满足您的需求,而且是最简单的方法。此运算符将成对的连续发射分组在一起,并将它们作为两个值的数组发射。
参见:http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise
或https://rxjs-dev.firebaseapp.com/api/operators/pairwise
更新:正如@courteouselk 在他的评论中指出的那样,我没有注意到这是一个 RxSwift 问题,而我的回答引用了一个 RxJS 解决方案(糟糕!)。
原来 RxSwift 没有 有一个内置的 pairwise
运算符,但是 RxSwiftExt provides a pairwise 扩展运算符类似于内置的 RxJS 运算符。
另一种扩展方式
extension ObservableType {
func withPrevious() -> Observable<(E?, E)> {
return scan([], accumulator: { (previous, current) in
Array(previous + [current]).suffix(2)
})
.map({ (arr) -> (previous: E?, current: E) in
(arr.count > 1 ? arr.first : nil, arr.last!)
})
}
}
用法:
someValue
.withPrevious()
.subscribe(onNext: { (previous, current) in
if let previous = previous { // previous is optional
print("previous: \(previous)")
}
print("current: \(current)")
})
.disposed(by: disposeBag)
我有一个变量,它是一个枚举值数组。这些值随时间变化。
enum Option {
case One
case Two
case Three
}
let options = Variable<[Option]>([ .One, .Two, .Three ])
然后我观察这个变量的变化。问题是,我需要知道最新值和先前值之间的差异。我目前正在这样做:
let previousOptions: [Option] = [ .One, .Two, .Three ]
...
options
.asObservable()
.subscribeNext { [unowned self] opts in
// Do some work diff'ing previousOptions and opt
// ....
self.previousOptions = opts
}
RxSwift 中是否有内置的东西可以更好地管理它?有没有办法始终从信号中获取先前值和当前值?
好了
options.asObservable()
.scan( [ [],[] ] ) { seed, newValue in
return [ seed[1], newValue ]
}
// optional, working with tuple of array is better than array of array
.map { array in (array[0], array[1]) }
//optional, in case you dont want empty array
.skipWhile { [=10=].count == 0 && .count == 0 }
它会 return Observable<([Options], [Options])>
:)
正如 Pham Hoan 所说,scan(_)
是完成这项工作的正确工具。 Marin Todorov 就此写了一篇 good post。
这是我根据 Marin 的 post 得出的结论:
options
.asObservable()
.scan([]) {
(previous, current) in
return Array(previous + [current]).suffix(2)
}
.subscribeNext {
(lastTwoOptions) in
let previousOptions = lastTwoOptions.first
let currentOptions = lastTwoOptions.last
// Do your thing. Remember to check for nil the first time around!
}
.addDisposableTo(self.disposeBag)
希望对您有所帮助
这是一个方便的通用扩展,应该涵盖这些 "I want the previous and the current value" 用例:
extension ObservableType {
func withPrevious(startWith first: E) -> Observable<(E, E)> {
return scan((first, first)) { ([=10=].1, ) }.skip(1)
}
}
我建议这样(对于未来的访问者):
options.asObservable()
.map { (old: [], new: [=10=]) } // change type from array to tuple
.scan((old: [], new: [])) { previous, current in
// seed with an empty tuple & return both information
return (old: previous.new, new: current.new)
}
.subscribe(onNext: { option in
let oldArray = option.old // old
let newArray = option.new // new
}
.addDisposableTo(disposeBag)
一行中的最佳解决方案:
Observable.zip(options, options.skip(1))
.pairwise()
运算符完全可以满足您的需求,而且是最简单的方法。此运算符将成对的连续发射分组在一起,并将它们作为两个值的数组发射。
参见:http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise
或https://rxjs-dev.firebaseapp.com/api/operators/pairwise
更新:正如@courteouselk 在他的评论中指出的那样,我没有注意到这是一个 RxSwift 问题,而我的回答引用了一个 RxJS 解决方案(糟糕!)。
原来 RxSwift 没有 有一个内置的 pairwise
运算符,但是 RxSwiftExt provides a pairwise 扩展运算符类似于内置的 RxJS 运算符。
另一种扩展方式
extension ObservableType {
func withPrevious() -> Observable<(E?, E)> {
return scan([], accumulator: { (previous, current) in
Array(previous + [current]).suffix(2)
})
.map({ (arr) -> (previous: E?, current: E) in
(arr.count > 1 ? arr.first : nil, arr.last!)
})
}
}
用法:
someValue
.withPrevious()
.subscribe(onNext: { (previous, current) in
if let previous = previous { // previous is optional
print("previous: \(previous)")
}
print("current: \(current)")
})
.disposed(by: disposeBag)