2番煎じかもしれませんが、ざっと探したら見つからなかったので。
他にあれば教えて下さい(笑い
##実装方針
- scanを使って、Bool値をtrue -> false -> true -> falseのように都度切り替えて流す
- そのBool値をつかって、filterする
let intSubject = PublishSubject<Int>()
let subject =
intSubject
.scan((true, 0)) { (output, update) -> (Bool, Int) in
//Bool値を反転して返してあげると、ストリームの度に値が変わることになる
//初期値はtrueを反転するのでfalseから始まる。結果として奇数回を飛ばすことになる
return (!output.0, update)
}
.compactMap { (flag, value) -> Int? in
flag ? value : nil
}
subject.bind { print($0) }
intSubject.onNext(1)
intSubject.onNext(2)
intSubject.onNext(3)
intSubject.onNext(4)
intSubject.onNext(5)
intSubject.onNext(6)
//結果
2
4
6
compactMap使ってますので、流す型がInt? だとおかしくなりますね。素直に filterとmapで書いたほうが良さそうです。あとはscanの初期値として渡している 0 も型を特定する以上の役割がないので要らないかなぁ
##汎用化してみました
extension をつかって、Observableの関数化してみます。
extension Observable {
//isEvenは偶数回だけイベントを流すか、奇数回だけにするかを決定するフラグ
func onceInTwice(isEven: Bool) -> Observable<Element> {
let initial: (Bool,[Element]) = (isEven, [])
return
scan(initial) { (output, update) -> (Bool, [Element]) in
return (!output.0, [update])
}
.filter { (flag, _) in return flag }
.map { (_, value) in return value.first! }
}
}
let input = PublishSubject<String?>()
let onceInTwice = input.onceInTwice(isEven: false)
onceInTwice.bind { print($0) }
input.onNext("1回目")
input.onNext("2回目")
input.onNext(nil)
input.onNext("4回目")
input.onNext("5回目")
input.onNext("6回目")
//結果
Optional("1回目")
nil
Optional("5回目")
期待どおりに動いてくれてそうです〜。