【Swift】RxSwiftのPlaygroundを読む⑤

RxSwiftのPlaygroundを読んでみるシリーズ今回は
条件如何で流したり、あるいは流さなかったりする操作についてです。
([Filtering_and_Conditional_Operators](https://github.com/ReactiveX/RxSwift/tree/master/Rx.playground/Pages/Filtering_and_Conditional_Operators.xcplaygroundpage))

# Filtering and Conditional Operators
様々に条件を設定し、条件に適えばそのまま値を流し、条件に合わなければ値を流しません。
堰のような役割をはたします。

## filter
流れてくる値に基づき条件を記述し、条件に合うものだけを流す。

```swift
let disposeBag = DisposeBag()

Observable.of(
    "🍑", "🍐", "🍎",
    "🍇", "🍑", "🍐",
    "🍎", "🍇", "🍑"
    )
    .filter {
        $0 == "🍑" // 🍑だけを流す
    }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍑)
Next(🍑)
Next(🍑)
Completed
```

## distinctUntilChanged
流れてくる値が、前回と違う値だったときのみ流す。

```swift
let disposeBag = DisposeBag()

Observable.of(
    "🍑", "🍑", "🍑",
    "🍎", "🍎", "🍎",
    "🍐", "🍐", "🍐"
    )
    .distinctUntilChanged()
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍑)
Next(🍎)
Next(🍐)
Completed
```

## elementAt
指定したインデックスの値のみ流す。

```swift
let disposeBag = DisposeBag()

Observable.of("🍑", "🍊", "🍇","🍎", "🍏", "🍉")
    .elementAt(4)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍏)
Completed
```

## single
流れてくる最初の値のみを流す。
あるいは、指定した条件に適う最初の値のみ流す。

条件を指定しない場合に2つ以上の値が流れてきたときや、
条件を指定した場合に、合うものが複数あったとき・合うものがなかったときはerrorが流れる。

**条件なし&流れる値が一つ**

```swift:no_condition_and_just
let disposeBag = DisposeBag()

Observable.just("🍑")
    .single()
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

```:結果
Next(🍑)
Completed
```

**条件なし&流れる値が複数**

```swift:no_condition_and_of
let disposeBag = DisposeBag()

Observable.of("🍑", "🍊", "🍇","🍎", "🍏", "🍉")
    .single()
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

```:結果
Next(🍑)
Error(Sequence contains more than one element.)
```

**条件あり&合うものが1つ**

```swift:condition_and_single
let disposeBag = DisposeBag()

Observable.of("🍊", "🍇","🍎", "🍑", "🍏", "🍉")
    .single { $0 == "🍑" }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

```:結果
Next(🍑)
Completed
```

**条件あり&合うものが複数**

```swift:condition_and_multiple
let disposeBag = DisposeBag()

Observable.of("🍊", "🍑","🍎", "🍑", "🍏", "🍉")
    .single { $0 == "🍑" }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

```:結果
Next(🍑)
Error(Sequence contains more than one element.)
```

**条件あり&合うものがない**

```swift:condition_and_nothing
let disposeBag = DisposeBag()

Observable.of("🍊", "🍇","🍎", "🍐", "🍏", "🍉")
    .single { $0 == "🍑" }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

```:結果
Error(Sequence doesn't contain any elements.)
```

## take
流れてきた順に指定した数の値を流す。

```swift
let disposeBag = DisposeBag()

Observable.of("🍊", "🍇","🍎", "🍑", "🍏", "🍉")
    .take(3)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍊)
Next(🍇)
Next(🍎)
Completed
```

## takeLast
後ろから数えて指定した数の値を流す。

```swift
let disposeBag = DisposeBag()

Observable.of("🍊", "🍇","🍎", "🍑", "🍏", "🍉")
    .takeLast(3)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍑)
Next(🍏)
Next(🍉)
Completed
```

## takeWhile
条件を満たさなくなるまでは値を流し、それ以降は(条件に合っていても)値を流さない。

```swift
let disposeBag = DisposeBag()

Observable.of("🍑", "🍑","🍑", "🍏", "🍑", "🍑")
    .takeWhile { $0 == "🍑" }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍑)
Next(🍑)
Next(🍑)
Completed
```

## takeUntil
参照する川を指定し、
その川に値が流れるまでは値を流し、
一度参照する川に値が流れると流さなくなる。

```swift
let disposeBag = DisposeBag()

let main川      = PublishSubject<String>()
let reference川 = PublishSubject<String>()

main川.takeUntil(reference川)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)

main川.onNext("🍑0")
main川.onNext("🍑1")

reference川.onNext("🍏")

main川.onNext("🍑2")
```

**結果**

```
Next(🍑0)
Next(🍑1)
Completed
```

## skip
流れてきた順に指定した数の値をスキップし、それ以降の値を流す。
takeと対照の関係。

```swift
let disposeBag = DisposeBag()

Observable.of("🍊", "🍇","🍎", "🍑", "🍏", "🍉")
    .skip(3)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍑)
Next(🍏)
Next(🍉)
Completed
```

## skipWhile
条件を満たす間は値をスキップし、それ以降は(条件に合っていても)値を流す。
takeWhileと対照の関係。

```swift
let disposeBag = DisposeBag()

Observable.of("🍑", "🍑","🍑", "🍏", "🍑", "🍑")
    .skipWhile { $0 == "🍑" }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍏)
Next(🍑)
Next(🍑)
Completed
```

## skipWhileWithIndex
skipWhileの条件の引数として、インデックスも受け取ることができる。

```swift
let disposeBag = DisposeBag()

Observable.of("🍑", "🍑","🍑", "🍏", "🍑", "🍑")
    .skipWhileWithIndex { element, index in
        index < 4
    }
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)
```

**結果**

```
Next(🍑)
Next(🍑)
Completed
```

## skipUntil
参照する川を指定し、
その川に値が流れるまでは値をスキップし、
一度参照する川に値が流れると値を流すようになる。
takeUntilと対照の関係。

```swift
let disposeBag = DisposeBag()

let main川      = PublishSubject<String>()
let reference川 = PublishSubject<String>()

main川.skipUntil(reference川)
    .subscribe { print($0) }
    .addDisposableTo(disposeBag)

main川.onNext("🍑0")
main川.onNext("🍑1")

reference川.onNext("🍏")

main川.onNext("🍑2")
```

**結果**

```
Next(🍑2)
```

# おわりに
この辺をうまく組み合わせることができれば、
変幻自在な川を作れそうです。

次回は流れる値を集める操作についてです。

# 参考
https://github.com/ReactiveX/RxSwift/tree/master/Rx.playground