Observed current and previous value

I have a variable that is an array of enum values. These values ​​change over time.

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

Then I observe this variable for changes. The problem is that I need to know the difference between the newest value and the previous value. I am doing this now:

 let previousOptions: [Option] = [ .One, .Two, .Three ] ... options .asObservable() .subscribeNext { [unowned self] opts in // Do some work diff'ing previousOptions and opt // .... self.previousOptions = opts } 

Is there something built into RxSwift that can handle this better? Is there a way to always get previous and current values ​​from a signal?

+8
source share
7 answers

there you go

 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 } 

it will return Observable<([Options], [Options])> :)

+8
source

Here is a small universal extension that should cover these "I want the previous and current value" use cases:

 extension ObservableType { func withPrevious(startWith first: E) -> Observable<(E, E)> { return scan((first, first)) { ($0.1, $1) }.skip(1) } } 
+10
source

As Fam Hoan said, scan(_) is the right tool for the job. Marin Todorov wrote a good post on how to do this.

Here's what I came up with based on a 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) 

hope this helps

+5
source

I would suggest something like this (for future visitors):

 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
source

The best solution in one line:

 Observable.zip(options, options.skip(1)) 
+1
source

The .pairwise() operator does exactly what you want, and this is the easiest way to do this. This operator combines pairs of consecutive outliers together and emits them as an array of two values.

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

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

0
source

Another way to expand

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

Using:

 someValue .withPrevious() .subscribe(onNext: { (previous, current) in if let previous = previous { // previous is optional print("previous: \(previous)") } print("current: \(current)") }) .disposed(by: disposeBag) 
0
source

Source: https://habr.com/ru/post/1245207/