8

Observable.TakeWhileを使用すると、条件が真である限りシーケンスを実行できます(デリゲートを使用して、実際のシーケンスオブジェクトで計算を実行できるようにします)が、各要素の前にこの条件をチェックします。各要素の後で同じチェックを実行するにはどうすればよいですか?

次のコードは問題を示しています

    void RunIt()
    {
        List<SomeCommand> listOfCommands = new List<SomeCommand>();
        listOfCommands.Add(new SomeCommand { CurrentIndex = 1, TotalCount = 3 });
        listOfCommands.Add(new SomeCommand { CurrentIndex = 2, TotalCount = 3 });
        listOfCommands.Add(new SomeCommand { CurrentIndex = 3, TotalCount = 3 });

        var obs = listOfCommands.ToObservable().TakeWhile(c => c.CurrentIndex != c.TotalCount);

        obs.Subscribe(x =>
        {
            Debug.WriteLine("{0} of {1}", x.CurrentIndex, x.TotalCount);
        });
    }

    class SomeCommand
    {
        public int CurrentIndex;
        public int TotalCount;
    }

この出力

1 of 3
2 of 3

3番目の要素を取得できません

この例を見ると、私がしなければならないのは私の状態をそのように変えることだけだと思う​​かもしれません-

var obs = listOfCommands.ToObservable().TakeWhile(c => c.CurrentIndex <= c.TotalCount);

しかし、その後、observableは決して完了しません(私の実際のコードでは、これらの3つのコマンドの後でストリームが終了しないため)

4

6 に答える 6

15

求めていることを実行するための組み込み演算子はありませんがPublish、基礎となるobservableを1回だけサブスクライブしながら、2つのクエリを実行するために使用する演算子を次に示します。

// Emits matching values, but includes the value that failed the filter
public static IObservable<T> TakeWhileInclusive<T>(
    this IObservable<T> source, Func<T, bool> predicate)
{
    return source.Publish(co => co.TakeWhile(predicate)
        .Merge(co.SkipWhile(predicate).Take(1)));
}

その後:

var obs = listOfCommands.ToObservable()
    .TakeWhileInclusive(c.CurrentIndex != c.TotalCount);
于 2013-02-05T03:11:10.153 に答える
6

最終編集:

このスレッドでのSergeyのTakeWhileInclusive実装に基づいてソリューションを作成しました- イベントの状態に応じてRxObservableを完了する方法

public static IObservable<TSource> TakeUntil<TSource>(
        this IObservable<TSource> source, Func<TSource, bool> predicate)
{
    return Observable
        .Create<TSource>(o => source.Subscribe(x =>
        {
            o.OnNext(x);
            if (predicate(x))
                o.OnCompleted();
        },
        o.OnError,
        o.OnCompleted
    ));
}
于 2013-02-12T21:15:14.153 に答える
2

演算子を使用してTakeUntil、セカンダリソースが値を生成するまですべてのアイテムを取得できます。この場合、述語が渡された後の最初の値として2番目のストリームを指定できます。

public static IObservable<TSource> TakeWhileInclusive<TSource>(
    this IObservable<TSource> source,
    Func<TSource, bool> predicate)
{
    return source.TakeUntil(source.SkipWhile(x => predicate(x)).Skip(1));
}
于 2013-02-05T12:32:05.817 に答える
1

私はあなたが後だと思いますTakeWhile、ではありませんTakeUntil

var list = (new List<int>(){1,2,3,4,5,6,7,8,9,10});
var takeWhile = list
        .ToObservable()
        .Select((_, i) => Tuple.Create(i, _))
        .TakeWhile(tup => tup.Item1 < list.Count)
        .Do(_ => Console.WriteLine("Outputting {0}", _.Item2));

わかりました、あなたが欲しいものは箱から出して存在しません、少なくとも私はその特定の構文で何かを知りません。そうは言っても、あなたはそれをかなり簡単に一緒に石畳にすることができます(そしてそれはそれほど厄介ではありません):

var fakeCmds = Enumerable
    .Range(1, 100)
    .Select(i => new SomeCommand() {CurrentIndex = i, TotalCount = 10})
    .ToObservable();

var beforeMatch = fakeCmds
    .TakeWhile(c => c.CurrentIndex != c.TotalCount);
var theMatch = fakeCmds
    .SkipWhile(c => c.CurrentIndex != c.TotalCount)
    .TakeWhile(c => c.CurrentIndex == c.TotalCount);
var upToAndIncluding = Observable.Concat(beforeMatch, theMatch);
于 2013-02-05T01:47:30.077 に答える
0

コンボ、新しいSkipUntilとを使用してTakeUntil

SkipUntil return source.Publish(s => s.SkipUntil(s.Where(predicate)));

TakeUntil (包括的) return source.Publish(s => s.TakeUntil(s.SkipUntil(predicate)));

完全なソースhttps ://gist.github.com/GeorgeTsiokos/a4985b812c4048c428a981468a965a86

于 2017-02-13T20:41:21.757 に答える
-1

おそらく、次の方法が誰かに役立つでしょう。「Do」メソッドと空の「Subscribe」メソッドを使用する必要があります。

    listOfCommands.ToObservable()
    .Do(x =>
    {
        Debug.WriteLine("{0} of {1}", x.CurrentIndex, x.TotalCount);
    })
    .TakeWhile(c => c.CurrentIndex != c.TotalCount)
    .Subscribe();

このようにして、独自の拡張機能を記述せずに結果を得ることができます。

于 2020-01-01T13:31:21.190 に答える