scan,groupjoin或groupbyuntil?

时间:2016-07-13 20:46:58

标签: c# system.reactive observable

假设有一些问题和答案,如下图所示。答案始终对应于最新的问题。

QUESTIONS: A     B      C        D
ANSWERS:     1 2         3 4 5    6

打印相应问题和答案的最佳方法是什么?以下是我使用Scan工作的解决方案。但是,我想知道是否有更直观的方法来使用GroupJoin完成此操作。我试过GroupJoin但是无法让它工作。我也很好奇GroupBy或GroupByUntil是否适合(但也无法使这些工作)。最后,这是我需要使用Publish的情况吗?

static void Main(string[] args) {
    var questions = new Subject<string>();
    var answers = new Subject<int>();
    var results = Observable
        .CombineLatest(
            questions,
            answers.StartWith(-1),
            (q, a) => new { Question = q, Answer = a })
        .Scan((a, b) =>
            (a.Question == b.Question)
            ? b
            : new { Question = b.Question, Answer = -1 });

    results.Subscribe(i => Console.WriteLine((i.Answer == -1) ? i.Question : $"  {i.Answer}"));

    questions.OnNext("A");
    answers.OnNext(1);
    answers.OnNext(2);
    questions.OnNext("B");
    questions.OnNext("C");
    answers.OnNext(3);
    answers.OnNext(4);
    answers.OnNext(5);
    questions.OnNext("D");
    answers.OnNext(6);

    Console.ReadLine();
}

预期输出为:

A
  1
  2
B
C
  3
  4
  5
D
  6

我想的越多,这个功能在数据库世界中就越像LeftJoin行为。我也能够使用类似你在下面看到的代码来使用它。出于某种原因,它不适用于控制台应用程序。当我用我自己的Versioned函数替换Timestamp函数(它指定递增的长值)时,它完美地工作。

var results = Observable
    .CombineLatest(questions.Timestamp(), answers.StartWith(-1).Timestamp(), (q, a) => new { Question = q, Answer = a })
    .Select(i => (i.Answer.Timestamp > i.Question.Timestamp)
        ? new { Question = i.Question.Value, Answer = i.Answer.Value }
        : new { Question = i.Question.Value, Answer = -1 });

2 个答案:

答案 0 :(得分:1)

以下是GroupJoin

的使用方法
var results = questions.GroupJoin(answers,
    s => questions,
    s => Observable.Empty<int>(),
    (q, a) => new { Question = q, Answers = a });

results2
    .Subscribe(i => 
    {
        Console.WriteLine(string.Format("{0}", i.Question));
        i.Answers.Subscribe(a => Console.WriteLine("  {0}", a));
    });

这会产生与您的代码相同的输出。

答案 1 :(得分:0)

可能更愚蠢了。 我认为最简单的答案是只使用合并并将两个序列投射到一个普通类型。 只需查看预期输出,您就可以看到它只是一个合并的序列。

var questions = new Subject<string>();
var answers = new Subject<int>();
var Qs = questions.Select(q => new { Question = q, Answer = -1});
var As = answers.Select(a => new { Question = (string)null, Answer = a});
Observable.Merge(Qs,As)
    .Subscribe(i => Console.WriteLine((i.Answer == -1) ? i.Question : $"  {i.Answer}"));

questions.OnNext("A");
answers.OnNext(1);
answers.OnNext(2);
questions.OnNext("B");
questions.OnNext("C");
answers.OnNext(3);
answers.OnNext(4);
answers.OnNext(5);
questions.OnNext("D");
answers.OnNext(6);

结果

A
  1
  2
B
C
  3
  4
  5
D
  6