scan, groupjoin, or groupbyuntil?

本文关键字:groupbyuntil groupjoin scan or | 更新日期: 2023-09-27 17:56:45

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

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

打印出相应问题和答案的最佳方法是什么?以下是我使用扫描获得的解决方案。但是,我想知道是否有一种更直观的方法来使用 GroupJoin 完成此操作。我尝试了GroupJoin,但无法让它工作。我也很好奇GroupBy 或 GroupByUntil 是否是合适的选择(但也无法让它们工作)。最后,这是我需要使用发布的情况吗?

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 行为。我还能够使用类似于您在下面看到的代码来使其工作。由于某种原因,它在控制台应用中不起作用。当我用我自己的版本化函数(分配递增的长值)替换时间戳函数时,它运行良好。

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 });

scan, groupjoin, or groupbyuntil?

以下是如何使用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));
    });

这将生成与代码相同的输出。

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

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