C# 是否有一个像Scan但让';让我返回一个可观察的<;TResult>;而不是IObservable<;t来源>;?

C# 是否有一个像Scan但让';让我返回一个可观察的<;TResult>;而不是IObservable<;t来源>;?,c#,system.reactive,C#,System.reactive,在这个纯粹为了实践而虚构的示例中,我想返回以下内容: var admissionObservable = Observable .FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted") .Timestamp() .Buffer(2) .Where(pair => pair[1].Timestamp - pair[0].Timesta

在这个纯粹为了实践而虚构的示例中,我想返回以下内容:

var admissionObservable = Observable
        .FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted")
        .Timestamp()
        .Buffer(2)
        .Where(pair => pair[1].Timestamp - pair[0].Timestamp <= timeSpan)
        .Select(pair => new JoiningData
        {
            Students = Tuple.Create(pair[0].Value.EventArgs.Student, pair[1].Value.EventArgs.Student),
            School = pair[0].Value.EventArgs.School,
            Interval = pair[1].Timestamp - pair[0].Timestamp
        });
如果两个学生在指定的时间段内加入一所学校,比如说2秒钟,那么我需要一个数据结构,返回两个学生、他们加入的学校以及他们加入之间的时间间隔

var admissionObservable = Observable
        .FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted")
        .Timestamp()
        .Buffer(2)
        .Where(pair => pair[1].Timestamp - pair[0].Timestamp <= timeSpan)
        .Select(pair => new JoiningData
        {
            Students = Tuple.Create(pair[0].Value.EventArgs.Student, pair[1].Value.EventArgs.Student),
            School = pair[0].Value.EventArgs.School,
            Interval = pair[1].Timestamp - pair[0].Timestamp
        });
我一直在这样想:

class Program
{
    static void Main(string[] args)
    {
        ObserveStudentsJoiningWithin(TimeSpan.FromSeconds(2));
    }

    static void ObserveStudentsJoiningWithin(TimeSpan timeSpan)
    {
        var school = new School("School 1");

        var admissionObservable =
            Observable.FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted");

        var observable = admissionObservable.TimeInterval()
            .Scan((current, next) =>
            {
                if (next.Interval - current.Interval <= timeSpan)
                {
                    // But this won't work for me because
                    // this requires me to return a TSource
                    // and not a TResult
                }
            });

        var subscription = observable.Subscribe(TimeIntervalValueHandler);

        school.FillWithStudentsAsync(10, TimeSpan.FromSeconds(3));
        school.FillWithStudentsAsync(8, TimeSpan.FromSeconds(1));

        Console.WriteLine("Press any key to exit the program");
        Console.ReadKey();
        subscription.Dispose();
    }
}
var admissionObservable = Observable
        .FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted")
        .Timestamp()
        .Buffer(2)
        .Where(pair => pair[1].Timestamp - pair[0].Timestamp <= timeSpan)
        .Select(pair => new JoiningData
        {
            Students = Tuple.Create(pair[0].Value.EventArgs.Student, pair[1].Value.EventArgs.Student),
            School = pair[0].Value.EventArgs.School,
            Interval = pair[1].Timestamp - pair[0].Timestamp
        });
类程序
{
静态void Main(字符串[]参数)
{
观察者在(从秒(2)开始的时间跨度)内进行观察;
}
静态void ObserveStudentsJoiningWithin(TimeSpan TimeSpan)
{
var学校=新学校(“学校1”);
可观察的风险值=
可观察。从事件模式(学校,“学生入学”);
var可观测=可观测的容许。时间间隔()
.Scan((当前,下一个)=>
{
if(next.Interval-current.Interval
  • 对于成对比较(原始-将当前项目与下一个项目一起投影),您可以使用一种方法构建成对序列
  • 为了找出学生之间的间隔,使用instead of方法可能更有用,因为下面的行
    next.interval-current.interval Tuple.Create(a,b))
    .Where(pair=>pair.Item2.Timestamp-pair.Item1.Timestamp new JoiningData
    {
    Students=Tuple.Create(pair.Item1.Value.EventArgs.Student,pair.Item2.Value.EventArgs.Student),
    学校=pair.Item1.Value.EventArgs.School,
    间隔=pair.Item2.Timestamp-pair.Item1.Timestamp
    });
    
    以下是我所做的:

    var admissionObservable = Observable
            .FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted")
            .Timestamp()
            .Buffer(2)
            .Where(pair => pair[1].Timestamp - pair[0].Timestamp <= timeSpan)
            .Select(pair => new JoiningData
            {
                Students = Tuple.Create(pair[0].Value.EventArgs.Student, pair[1].Value.EventArgs.Student),
                School = pair[0].Value.EventArgs.School,
                Interval = pair[1].Timestamp - pair[0].Timestamp
            });
    
    static void ObserveStudentsJoiningWithin(TimeSpan timeSpan)
    {
        var school = new School("School 1");
    
        var admissionObservable =
            Observable.FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted");
    
        var observable = admissionObservable.TimeInterval()
            .Scan<TimeInterval<EventPattern<StudentAdmittedEventArgs>>, StudentPair>(null, (previousPair, current) =>
            {
                Debug.Print(string.Format($"Student joined after {current.Interval.TotalSeconds} seconds, timeSpan = {timeSpan.TotalSeconds} seconds"));
    
                var pair = new StudentPair();
    
                if (previousPair == null)
                {
                    pair.FirstStudent = null;
                    pair.SecondStudent = current.Value.EventArgs.Student;
                    pair.IntervalBetweenJoining = current.Interval;
                    pair.School = current.Value.EventArgs.School;
    
                    return pair;
                }
    
                if (current.Interval <= timeSpan)
                {
                    pair.FirstStudent = previousPair.SecondStudent;
                    pair.SecondStudent = current.Value.EventArgs.Student;
                    pair.IntervalBetweenJoining = current.Interval;
                    pair.School = current.Value.EventArgs.School;
    
                    return pair;
                }
                else
                {
                    return default(StudentPair);
                }
            })
            .Where(p => (p != default(StudentPair)) && (p.FirstStudent != null));
    
        var subscription = observable.Subscribe(StudentPairValueHandler);
    
        school.FillWithStudents(4, TimeSpan.FromSeconds(1));
        school.FillWithStudents(2, TimeSpan.FromSeconds(10));
        school.FillWithStudents(3, TimeSpan.FromSeconds(2));
        school.FillWithStudents(2, TimeSpan.FromSeconds(5));
        school.FillWithStudents(5, TimeSpan.FromSeconds(0.6));
    
        Console.WriteLine("Press any key to exit the program");
        Console.ReadKey();
        subscription.Dispose();
    }
    
    static void StudentPairValueHandler(StudentPair pair)
    {
        if (pair != null && pair.FirstStudent != null)
        {
            Console.WriteLine($"{pair.SecondStudent.Name} joined {pair.School.Name} {Math.Round(pair.IntervalBetweenJoining.TotalSeconds, 2)} seconds after {pair.FirstStudent.Name}.");
        }
    }
    
    ...
    
    public class StudentPair
    {
        public Student FirstStudent;
        public Student SecondStudent;
        public School School;
        public TimeSpan IntervalBetweenJoining;
    }
    
    
    public static class Extensions
    {
        public static void FillWithStudents(this School school, int howMany)
        {
            FillWithStudents(school, howMany, TimeSpan.Zero);
        }
    
        public static void FillWithStudents(this School school, int howMany, TimeSpan gapBetweenEachAdmission)
        {
            if (school == null)
                throw new ArgumentNullException("school");
    
            if (howMany < 0)
                throw new ArgumentOutOfRangeException("howMany");
    
            if (howMany == 1)
            {
                school.AdmitStudent(Student.CreateRandom());
                return;
            }
    
            for (int i = 0; i < howMany; i++)
            {
                Thread.Sleep((int)gapBetweenEachAdmission.TotalMilliseconds);
    
                school.AdmitStudent(Student.CreateRandom());
            }
        }
    
        public async static void FillWithStudentsAsync(this School school, int howMany, TimeSpan gapBetweenEachAdmission)
        {
            if (school == null)
                throw new ArgumentNullException("school");
    
            if (howMany < 0)
                throw new ArgumentOutOfRangeException("howMany");
    
            if (howMany == 1)
            {
                school.AdmitStudent(Student.CreateRandom());
                return;
            }
    
            for (int i = 0; i < howMany; i++)
            {
                await Task.Delay(gapBetweenEachAdmission);
    
                school.AdmitStudent(Student.CreateRandom());
            }
        }
    }
    
    static void ObserveStudentsJoiningWithin(TimeSpan TimeSpan)
    {
    var学校=新学校(“学校1”);
    可观察的风险值=
    可观察。从事件模式(学校,“学生入学”);
    var可观测=可观测的容许。时间间隔()
    .Scan(空,(上一对,当前)=>
    {
    Print(string.Format($“Student在{current.Interval.TotalSeconds}秒之后加入,timeSpan={timeSpan.TotalSeconds}秒”);
    var pair=新的StudentPair();
    if(previousPair==null)
    {
    pair.firstststudent=null;
    pair.SecondStudent=current.Value.EventArgs.Student;
    pair.IntervalBetweenJoining=当前.Interval;
    pair.School=current.Value.EventArgs.School;
    返回对;
    }
    if(current.Interval(p!=default(StudentPair))&&(p.firstststudent!=null));
    var subscription=observable.subscripte(StudentPairValueHandler);
    学校。填充学生(4,时间跨度从秒(1));
    学校。填充学生(2,时间跨度从秒(10));
    学校。填充学生(3,时间跨度。从秒(2));
    学校。填充学生(2,时间跨度从秒(5));
    学校。填充学生(5,时间跨度从秒(0.6));
    Console.WriteLine(“按任意键退出程序”);
    Console.ReadKey();
    subscription.Dispose();
    }
    静态无效StudentPairValueHandler(StudentPair)
    {
    if(pair!=null&&pair.firstststudent!=null)
    {
    WriteLine($“{pair.SecondStudent.Name}在{pair.firstststudent.Name}之后加入{pair.School.Name}{Math.Round(pair.intervalbetweenjoin.TotalSeconds,2)}秒);
    }
    }
    ...
    公共班级学生对
    {
    公立学生第一名;
    公立学校学生;
    公立学校;
    连接之间的公共时间间隔;
    }
    公共静态类扩展
    {
    公立学校和学生(这所学校,有多少人)
    {
    填充学生(学校、数量、时间跨度为零);
    }
    公共静态空白填充学生(此学校,int多少,每个任务之间的时间间隔)
    {
    如果(学校==null)
    抛出新的异常(“学校”);
    如果(有多少个<0)
    抛出新ArgumentOutOfRangeException(“多少”);
    如果(数量==1)
    {
    school.AdmitStudent(Student.CreateRandom());
    返回;
    }
    for(int i=0;i<多少;i++)
    {
    Sleep((int)间隙介于eachadmission.total毫秒之间);
    school.AdmitStudent(Student.CreateRandom());
    }
    }
    公共异步静态void FillWithStudentsAsync(此学校,整数,每个任务之间的时间间隔)
    {
    如果(学校==null)
    抛出新的异常(“学校”);
    如果(有多少个<0)
    抛出新ArgumentOutOfRangeException(“多少”);
    如果(数量==1)
    {
    school.AdmitStudent(Student.CreateRandom());
    返回;
    }
    for(int i=0;i<多少;i++)
    {
    等待任务。延迟(每个任务之间的间隙);
    school.AdmitStudent(Student.CreateRandom());
    }
    }
    }
    
    你能试试这个,看看它是否能满足你的需要吗

    var admissionObservable = Observable
            .FromEventPattern<StudentAdmittedEventArgs>(school, "StudentAdmitted")
            .Timestamp()
            .Buffer(2)
            .Where(pair => pair[1].Timestamp - pair[0].Timestamp <= timeSpan)
            .Select(pair => new JoiningData
            {
                Students = Tuple.Create(pair[0].Value.EventArgs.Student, pair[1].Value.EventArgs.Student),
                School = pair[0].Value.EventArgs.School,
                Interval = pair[1].Timestamp - pair[0].Timestamp
            });
    
    IObservable<EventPattern<StudentAdmittedEventArgs>[]> observable =
        admissionObservable
            .Publish(pxs =>
                pxs
                    .Window(pxs, x => Observable.Timer(timeSpan))
                    .Select(ys => ys.Take(2)))
            .SelectMany(ys => ys.ToArray())
            .Where(ys => ys.Skip(1).Any());
    
    i可观察=
    可观察到的承认
    .Publish(pxs=>
    pxs
    .Window(pxs,x=>Observable.Timer(timeSpan))
    .Select(ys=>ys.Take(2)))
    .SelectMany(ys=>ys.ToArray())
    其中(ys=>ys.Skip(1.Any());
    
    允许你返回累加器类型。我的错。你是对的。如果你把它作为一个答案写下来?真的很漂亮。非常感谢。我已经用
    扫描
    实现了它,很快就会发布它。关于
    If
    条件,你是对的。我不得不更改它,因为它是错误的。但这是一个非常有趣的会议方法。因为在使用
    Scan
    完成我的解决方案之前,我实际上想知道我是否应该记录
    DateTime
    一名学生在
    accepted
    事件中被录取,并将该信息与
    EventArgs
    一起发送。事实证明,我可以不使用
    Scan
    来记录这些信息,但是这样做了