代码之家  ›  专栏  ›  技术社区  ›  Tobias von Falkenhayn

在前一个元素与条件匹配后获取流的第一个元素

  •  2
  • Tobias von Falkenhayn  · 技术社区  · 6 年前

    我有一个包含字符串和bool属性的对象的流传入。这条河将是无限的。我有以下条件:

    • 现在,应该跳过所有传入对象,直到对象到达时bool属性设置为“true”。
    • 现在这样,属性设置为true的对象后面的每个对象都应该被打印出来。

    例子:

    ("one", false)--("two", true)--("three", false)--("four", false)--("five", true)--("six", true)--("seven", true)--("eight", false)--("nine", true)--("ten", false)
    

    预期结果:

    "one"--"three"--"six"--"seven"--"eight"--"ten"
    

    测试它的简单.NET程序:

    using System;
    using System.Reactive.Linq;
    using System.Threading;
    
    namespace ConsoleApp1
    {
        class Program
        {
            class Result
            {
                public bool Flag { get; set; }
                public string Text { get; set; }
            }
    
            static void Main(string[] args)
            {               
                var source =
                   Observable.Create<Result>(f =>
                   {
                       f.OnNext(new Result() { Text = "one", Flag = false });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "two", Flag = true });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "three", Flag = false });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "four", Flag = false });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "five", Flag = true });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "six", Flag = true });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "seven", Flag = true });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "eight", Flag = false });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "nine", Flag = true });
                       Thread.Sleep(1000);
                       f.OnNext(new Result() { Text = "ten", Flag = false });
    
                       return () => Console.WriteLine("Observer has unsubscribed");
                   });
            }
        }
    }
    

    .Scan .Buffer 但我不知道如何在我的场景中使用它们。

    性能当然应该尽可能好,因为最终流会是无限的。

    4 回复  |  直到 6 年前
        1
  •  3
  •   Enigmativity    6 年前

    尝试以下方法:

    var results = new[]
    {
        new Result() { Text = "one", Flag = false },
        new Result() { Text = "two", Flag = true },
        new Result() { Text = "three", Flag = false },
        new Result() { Text = "four", Flag = false },
        new Result() { Text = "five", Flag = true },
        new Result() { Text = "six", Flag = true },
        new Result() { Text = "seven", Flag = true },
        new Result() { Text = "eight", Flag = false },
        new Result() { Text = "nine", Flag = true },
        new Result() { Text = "ten", Flag = false },
    };
    
    IObservable<Result> source =
        Observable
            .Generate(
                0, x => x < results.Length, x => x + 1,
                x => results[x],
                x => TimeSpan.FromSeconds(1.0));
    

    source 比你的 Observable.Create<Result>

    现在是 query :

    IObservable<Result> query =
        source
            .StartWith(new Result() { Flag = true })
            .Publish(ss =>
                ss
                    .Skip(1)
                    .Zip(ss, (s1, s0) =>
                        s0.Flag
                        ? Observable.Return(s1) 
                        : Observable.Empty<Result>())
                    .Merge());
    

    .Publish 这里允许源observable只有一个订阅,但是在 。发布 Skip(1).Zip 方法可用于检查正在生成的后续值。

    输出如下:

    output


    .Buffer(2, 1) :

    IObservable<Result> query2 =
        source
            .StartWith(new Result() { Flag = true })
            .Buffer(2, 1)
            .Where(rs => rs.First().Flag)
            .SelectMany(rs => rs.Skip(1));
    
        2
  •  2
  •   Shlomo    6 年前

    有很多方法可以做到这一点:

    var result1 = source.Publish(_source => _source
        .Zip(_source.Skip(1), (older, newer) => (older, newer))
        .Where(t => t.older.Flag == true)
        .Select(t => t.newer)
        .Merge(_source.Take(1))
        .Select(r => r.Text)
    );
    
    var result2 = source.Publish(_source => _source
        .Buffer(2, 1)
        .Where(l => l[0].Flag == true)
        .Select(l => l[1])
        .Merge(_source.Take(1))
        .Select(l => l.Text)
    );
    
    var result3 = source.Publish(_source => _source
        .Window(2, 1)
        .SelectMany(w => w
            .TakeWhile((r, index) => (index == 0 && r.Flag) || index == 1)
            .Skip(1)
        )
        .Merge(_source.Take(1))
        .Select(l => l.Text)
    );
    
    var result4 = source
        .Scan((result: new Result {Flag = true, Text = null}, emit: false), (state, r) => (r, state.result.Flag))
        .Where(t => t.emit)
        .Select(t => t.result.Text);
    

        3
  •  0
  •   Tobias von Falkenhayn    6 年前

    感谢@Picci的回答,我找到了一种方法:

    Func<bool, Action<Result>> printItem = print =>
                    {
                        return data => {
                            if(print)
                            {
                                Console.WriteLine(data.Text);
                            }
                        };
                    };
    
    var printItemFunction = printItem(true);
    
    source.Do(item => printItemFunction(item))
          .Do(item => printItemFunction = printItem(item.Flag))
          .Subscribe();
    

        4
  •  -1
  •   Picci    6 年前

    这就是我用打字机编码的方法

    const printItem = (print: boolean) => {
        return (data) => {
            if (print) {
                console.log(data);
            }
        };
    }
    
    let printItemFunction = printItem(true);
    
    from(data)
    .pipe(
        tap(item => printItemFunction(item.data)),
        tap(item => printItemFunction = printItem(item.printBool))
    )
    .subscribe()
    

    printItem ,它返回一个知道是否打印以及打印什么的函数。返回的函数存储在变量中, printItemFunction .

    对于可观测源发出的每个项,首先要执行 printitem函数

    第二件事是评估 打印项目 函数并将结果存储在变量中 printitem函数 以便它准备好接受以下通知。

    printitem函数 初始化为 true

    我不熟悉C#给你一个.NET的答案