可观察的当前和先前价值

Ste*_*ker 11 swift rx-swift

我有一个变量,它是一个枚举值数组.这些值随时间而变化.

enum Option {
    case One
    case Two
    case Three
}

let options = Variable<[Option]>([ .One, .Two, .Three ])
Run Code Online (Sandbox Code Playgroud)

然后我观察这个变量的变化.问题是,我需要知道最新值和前一个值之间的差异.我现在正在这样做:

let previousOptions: [Option] = [ .One, .Two, .Three ]

...

options
    .asObservable()
    .subscribeNext { [unowned self] opts in
        // Do some work diff'ing previousOptions and opt
        // ....
        self.previousOptions = opts
    }
Run Code Online (Sandbox Code Playgroud)

是否内置了RxSwift可以更好地管理它?有没有办法始终从信号中获取先前值和当前值?

小智 20

这是一个方便的通用扩展,应该涵盖这些"我想要前一个和当前值"的用例:

extension ObservableType {

    func withPrevious(startWith first: E) -> Observable<(E, E)> {
        return scan((first, first)) { ($0.1, $1) }.skip(1)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此方法永远不会发出包含作为参数提供的“first”元素的元组,请考虑删除“.skip(1)” (2认同)

ric*_*chy 11

另一种方式作为扩展

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!)
      })
  }
}
Run Code Online (Sandbox Code Playgroud)

用法:

someValue
  .withPrevious()
  .subscribe(onNext: { (previous, current) in
    if let previous = previous { // previous is optional
      print("previous: \(previous)")
    }
    print("current: \(current)")
  })
  .disposed(by: disposeBag)
Run Code Online (Sandbox Code Playgroud)


Pha*_*oan 10

你去吧

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 { $0.count == 0 && $1.count == 0 }
Run Code Online (Sandbox Code Playgroud)

它会返回Observable<([Options], [Options])>:)


Pau*_*aul 6

Pham Hoan说,这scan(_)是工作的正确工具.Marin Todorov撰写了一篇关于做到这一点的好文章.

基于Marin的帖子,这就是我提出的内容:

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)
Run Code Online (Sandbox Code Playgroud)

希望有所帮助


jjj*_*jjs 6

.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提供了成对类似于内置RxJS运营商的扩展操作。