知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UniRx】メッセージをフィルタリングするオペレータ #94

前回の成果

ファクトリメソッド系のオペレータについて学んだ。

soramamenatan.hatenablog.com


今回やること

今回はメッセージのフィルタのオペレータについてまとめます。


メッセージのフィルタ

流れてきたメッセージをフィルタリングするメソッド群になります。

条件を満たすものを流す

Where
/// <summary>
/// 条件を満たすものを流す
/// </summary>
private void ExcuteWhere() {
    Subject<int> subject = new Subject<int>();
    subject
        .Where(x => x > 10)
        .Subscribe(x => {
            Debug.Log("Where : " + x);
        });
    // 流れない
    subject.OnNext(1);
    // 流れない
    subject.OnNext(10);
    // 流れる
    subject.OnNext(100);
}
結果

f:id:soramamenatan:20210307120111p:plain


1度流れたものは流さない

Distinct
/// <summary>
/// 1度流れたものは流さない
/// </summary>
private void ExcuteDistinct() {
    Subject<int> subject = new Subject<int>();
    subject
        .Distinct()
        .Subscribe(x => {
            Debug.Log("Distinct : " + x);
        });
    // 流れる
    subject.OnNext(1);
    // 流れない
    subject.OnNext(1);
    // 流れる
    subject.OnNext(0);
    // 流れない
    subject.OnNext(1);
    // 流れない
    subject.OnNext(0);
}
結果

f:id:soramamenatan:20210307120235p:plain


値が前回と異なる場合に流す

DistinctUntilChanged
/// <summary>
/// 値が前回と異なる場合に流す
/// </summary>
private void ExcuteDistinctUntilChanged() {
    Subject<int> subject = new Subject<int>();
    subject
        .DistinctUntilChanged()
        .Subscribe(x => {
            Debug.Log("DistinctUntilChanged : " + x);
        });
    // 流れる
    subject.OnNext(1);
    // 流れない
    subject.OnNext(1);
    // 流れる
    subject.OnNext(0);
    // 流れる
    subject.OnNext(1);
    // 流れる
    subject.OnNext(0);
}
結果

f:id:soramamenatan:20210307120430p:plain


指定した時間値が流れてこなかったら最後のonNextを流す

秒の代わりにフレームを指定する、ThrottleFrameも存在します。

Throttle
/// <summary>
/// 指定した時間値が流れてこなかったら最後のonNextを流す
/// </summary>
private void ExcuteThrottle() {
    this.UpdateAsObservable()
        .Where(_ => Input.anyKeyDown)
        .Throttle(TimeSpan.FromSeconds(2))
        .Subscribe(_ => {
            Debug.Log("Throttle");
        });
}
結果

上の例の場合ですと、何かキーを押してから2秒間何もキーを押さないとメッセージが発行されます。

f:id:soramamenatan:20210307121020p:plain


最初は値を流し、指定した時間は流さないを繰り返す

秒の代わりにフレームを指定する、ThrottleFirstFrameも存在します。

ThrottleFirst
/// <summary>
/// 最初は値を流し、指定した時間は流さないを繰り返す
/// </summary>
private void ExcuteThrottleFirst() {
    this.UpdateAsObservable()
        .ThrottleFirst(TimeSpan.FromSeconds(1))
        .Subscribe(_ => {
            Debug.Log("ThrottleFirst");
        });
}
結果

f:id:soramamenatan:20210307142136p:plain


最初のonNextのみ通し、onCompletedを発行

値を一度も流さずにonCompletedを呼ぶとエラーになってしまいます。 値を一度も流さずにonCompletedを呼びたい場合はFirstOrDefaultを使用してください。

First
/// <summary>
/// 最初のonNextのみ通し、onCompletedを発行
/// </summary>
private void ExcuteFirst() {
    Subject<int> subject = new Subject<int>();
    subject
        .First()
        .Subscribe(x => {
            Debug.Log("First onNext : " + x);
        }, () => {
            Debug.Log("First onCompleted");
        });
    // 流れる
    subject.OnNext(1);
    // 流れない
    subject.OnNext(10);
    // 流れない
    subject.OnNext(100);
}
結果

f:id:soramamenatan:20210307142352p:plain


onCompletedを発行した時点での最後の値を発行

値を一度も流さずにonCompletedを呼ぶとエラーになってしまいます。 値を一度も流さずにonCompletedを呼びたい場合はLastOrDefaultを使用してください。

Last
/// <summary>
/// onCompletedを発行した時点での最後の値を発行
/// </summary>
private void ExcuteLast() {
    Subject<int> subject = new Subject<int>();
    subject
        .Last()
        .Subscribe(x => {
            Debug.Log("Last onNext : " + x);
        }, () => {
            Debug.Log("Last onCompleted");
        });
    // 流れない
    subject.OnNext(1);
    // 流れない
    subject.OnNext(10);
    // 流れる
    subject.OnNext(100);
    subject.OnCompleted();
}
結果

f:id:soramamenatan:20210307142926p:plain


OnNextが2回以上流れたら、onErrorを発行

値を一度も流さずにonCompletedを呼ぶとエラーになってしまいます。 値を一度も流さずにonCompletedを呼びたい場合はSingleOrDefaultを使用してください。

Single
/// <summary>
/// OnNextが2回以上流れたら、onErrorを発行
/// </summary>
private void ExcuteSingle() {
    Subject<int> subject = new Subject<int>();
    subject
        .Single()
        .Subscribe(x => {
            Debug.Log("Single onNext : " + x);
        }, err => {
            Debug.Log("Single onError : " + err);
        });
    subject.OnNext(1);
    // onErrorを発行
    subject.OnNext(10);
}
結果

f:id:soramamenatan:20210307143056p:plain


指定した数だけ流す

Take
/// <summary>
/// 指定した数だけ流す
/// </summary>
private void ExcuteTake() {
    Subject<int> subject = new Subject<int>();
    int count = 3;
    subject
        .Take(count)
        .Subscribe(x => {
            Debug.Log("Take onNext : " + x);
        });
    // 流れる
    subject.OnNext(1);
    // 流れる
    subject.OnNext(10);
    // 流れる
    subject.OnNext(100);
    // 流れない
    subject.OnNext(1000);
    // 流れない
    subject.OnNext(10000);
}
結果

f:id:soramamenatan:20210307143451p:plain


指定した条件を満たしている間は流し、一度でも満たしていないものが来たら以降は流さない

TakeWhile
/// <summary>
/// 指定した条件を満たしている間は流し、一度でも満たしていないものが来たら以降は流さない
/// </summary>
private void ExcuteTakeWhile() {
    Subject<int> subject = new Subject<int>();
    subject
        .TakeWhile(x => x > 10)
        .Subscribe(x => {
            Debug.Log("TakeWhile onNext : " + x);
        });
    // 流れる
    subject.OnNext(100);
    // 流れる
    subject.OnNext(1000);
    // 流れない
    subject.OnNext(10);
    // 流れない
    subject.OnNext(10000);
    // 流れない
    subject.OnNext(100000);
}
結果

f:id:soramamenatan:20210307143537p:plain


指定したObservableのonNextが発行されるまで流す

TakeUntil
/// <summary>
/// 指定したObservableのonNextが発行されるまで流す
/// </summary>
private void ExcuteTakeUntil() {
    Subject<int> subject = new Subject<int>();
    Subject<int> otherSubject = new Subject<int>();
    subject
        .TakeUntil(otherSubject)
        .Subscribe(x => {
            Debug.Log("TakeUntil onNext : " + x);
        });
    // 流れる
    subject.OnNext(1);
    // 流れる
    subject.OnNext(10);
    otherSubject.OnNext(1);
    // 流れない
    subject.OnNext(100);
}
結果

f:id:soramamenatan:20210307143734p:plain


指定した数流さず、それ以降は流す

Skip
/// <summary>
/// 指定した数流さず、それ以降は流す
/// </summary>
private void ExcuteSkip() {
    Subject<int> subject = new Subject<int>();
    int count = 3;
    subject
        .Skip(count)
        .Subscribe(x => {
            Debug.Log("Skip onNext : " + x);
        });
    // 流れない
    subject.OnNext(1);
    // 流れない
    subject.OnNext(10);
    // 流れない
    subject.OnNext(100);
    // 流れる
    subject.OnNext(1000);
    // 流れる
    subject.OnNext(10000);
}
結果

f:id:soramamenatan:20210307143820p:plain


指定した条件を満たしている間は流さず、一度でも満たしているものが来たら以降は流す

SkipWhile
/// <summary>
/// 指定した条件を満たしている間は流さず、一度でも満たしているものが来たら以降は流す
/// </summary>
private void ExcuteSkipWhile() {
    Subject<int> subject = new Subject<int>();
    subject
        .SkipWhile(x => x > 10)
        .Subscribe(x => {
            Debug.Log("SkipWhile : onNext : " + x);
        });
    // 流れない
    subject.OnNext(100);
    // 流れない
    subject.OnNext(1000);
    // 流れる
    subject.OnNext(10);
    // 流れる
    subject.OnNext(10000);
    // 流れる
    subject.OnNext(100000);
}
結果

f:id:soramamenatan:20210307143908p:plain


指定したObservableのonNextが発行されるまで流さない

SkipUntil
/// <summary>
/// 指定したObservableのonNextが発行されるまで流さない
/// </summary>
private void ExcuteSkipUntil() {
    Subject<int> subject = new Subject<int>();
    Subject<int> otherSubject = new Subject<int>();
    subject
        .SkipUntil(otherSubject)
        .Subscribe(x => {
            Debug.Log("SkipUntil onNext : " + x);
        });
    // 流れない
    subject.OnNext(1);
    // 流れない
    subject.OnNext(10);
    otherSubject.OnNext(1);
    // 流れる
    subject.OnNext(100);
}
結果

f:id:soramamenatan:20210307143946p:plain


OnErrorかonCompletedのみ流し、onNextは流さない

IgnoreElements
/// <summary>
/// OnErrorかonCompletedのみ流し、onNextは流さない
/// </summary>
private void ExcuteIgnoreElements() {
    Subject<int> subject = new Subject<int>();
    subject
        .IgnoreElements()
        .Subscribe(x => {
            Debug.Log("IgnoreElements onNext : " + x);
        }, err => {
            Debug.Log("IgnoreElements onError : " + err);
        }, () => {
            Debug.Log("IgnoreElements onCompleted ");
        });
    // 流れない
    subject.OnNext(1);
    // 流れる
    subject.OnError(new System.Exception("error"));
    // この例だと流れないが、流れる
    subject.OnCompleted();
}
結果

f:id:soramamenatan:20210307144035p:plain


今回は以上となります。
ここまでご視聴ありがとうございました。


参考サイト様

qiita.com