web-dev-qa-db-ja.com

観測可能な現在および以前の値

列挙値の配列である変数があります。これらの値は時間とともに変化します。

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に組み込まれているものはありますか?常に信号から以前の値と現在の値を取得する方法はありますか?

16

そこに行きます

_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 }
_

Observable<([Options], [Options])>を返します:)

12
Pham Hoan

以下は、これらをカバーする便利な汎用拡張です"私は以前の値と現在の値が必要です"使用例:

extension ObservableType {

    func withPrevious(startWith first: E) -> Observable<(E, E)> {
        return scan((first, first)) { ($0.1, $1) }.skip(1)
    }
}
22
retendo

Pham Hoanが言ったように、scan(_)はその仕事に適したツールです。 Marin Todorovさんは、まさにこれを行うことについて good 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)

それが役に立てば幸い

7
Paul

拡張としての別の方法

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)
3
richy

1行での最適なソリューション:

Observable.Zip(options, options.skip(1))
1
duan

私はこのようなものを提案します(将来の訪問者向け):

options.asObservable()
       .map { (old: [], new: $0) }   // 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)
1
sCha

.pairwise()演算子は、まさに望みどおりのことを行い、それを行う最も簡単な方法です。この演算子は、連続する放出のペアをグループ化し、2つの値の配列として放出します。

参照: 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演算子に似た拡張演算子。

1
jjjjs