web-dev-qa-db-fra.com

Valeur actuelle et précédente observable

J'ai une variable qui est un tableau de valeurs énumérées. Ces valeurs changent avec le temps.

enum Option {
    case One
    case Two
    case Three
}

let options = Variable<[Option]>([ .One, .Two, .Three ])

J'observe ensuite cette variable pour les changements. Le problème est que j'ai besoin de connaître la différence entre la valeur la plus récente et la valeur précédente. Je fais actuellement ceci:

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

...

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

Y a-t-il quelque chose de intégré à RxSwift qui pourrait mieux gérer cela? Existe-t-il un moyen d'obtenir toujours les valeurs précédentes et actuelles d'un signal?

16

voilà

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 }

il renverra Observable<([Options], [Options])> :)

12
Pham Hoan

Voici une extension générique pratique, qui devrait couvrir ces "Je veux la valeur précédente et la valeur actuelle" cas d'utilisation:

extension ObservableType {

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

Comme l'a dit Pham Hoan, scan(_) est le bon outil pour le travail. Marin Todorov a écrit un bon article pour faire exactement cela.

Voici ce que j'ai trouvé, basé sur le post de 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)

J'espère que cela pourra aider

7
Paul

Une autre façon comme extension

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!)
      })
  }
}

Usage:

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

Meilleure solution en une seule ligne:

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

Je suggérerais quelque chose comme ça (pour les futurs visiteurs):

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

L'opérateur .pairwise() fait exactement ce que vous voulez et est le moyen le plus simple de le faire. Cet opérateur regroupe des paires d'émissions consécutives et les émet sous la forme d'un tableau de deux valeurs.

voir: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise

ou https://rxjs-dev.firebaseapp.com/api/operators/pairwise


MISE À JOUR: comme @courteouselk l'a souligné dans son commentaire, je n'ai pas remarqué qu'il s'agissait d'une question RxSwift, et ma réponse faisait référence à une solution RxJS (oups!).

Il s'avère que RxSwift n'a pas un opérateur pairwise intégré, mais RxSwiftExt fournit un par paire opérateur d'extension similaire à l'opérateur RxJS intégré.

1
jjjjs