C# 两组数据的交集

C# 两组数据的交集,c#,algorithm,datetime,intersection,C#,Algorithm,Datetime,Intersection,在过去的一周半里,我一直在绞尽脑汁研究这个算法,但我无法让它工作 基本上我有一个时间表(我知道“边界”的时间价值) 我有红色部分(人们进出工作场所的运动)。我想知道的是人们在工作时间内的安排,我不在乎他们是在上班前还是下班后,还是在午餐休息时间 你有什么建议吗?关于我可以在这里应用的数学理论或规则?或者你见过的一个类似的问题,你能指给我看吗?我一直很难找到解决办法。任何帮助都将不胜感激 例如: 日程安排: 上午7:30(开始)下午12:00(午休) 下午1:30(午休结束)下午5:00(工作日

在过去的一周半里,我一直在绞尽脑汁研究这个算法,但我无法让它工作

基本上我有一个时间表(我知道“边界”的时间价值) 我有红色部分(人们进出工作场所的运动)。我想知道的是人们在工作时间内的安排,我不在乎他们是在上班前还是下班后,还是在午餐休息时间

你有什么建议吗?关于我可以在这里应用的数学理论或规则?或者你见过的一个类似的问题,你能指给我看吗?我一直很难找到解决办法。任何帮助都将不胜感激

例如:

日程安排:
上午7:30(开始)下午12:00(午休)
下午1:30(午休结束)下午5:00(工作日结束)

一天中的人员流动:
进站时间:上午6:50,出站时间:上午6:55
上午7:00进站,上午11:45出站
进:下午1:45,出:下午5:05


因此,我的预期输出时间跨度为:7:30(它忽略了工作日程之外的工作时间)

将一天分成1440个一分钟的增量。这是您的设置空间

  • Set“S”(预定的分钟数)是该空间的子集
  • 设置“W”,即在作业上花费的时间量,是该空间的子集
“S”和“W”的交叉点是该人员在其计划内的停留时间(以分钟为单位-根据您的需要转换为hh:mm)


使用其他集合算法,您可以找到它们本应存在但不存在的时间,等等。

将一天分成1440个一分钟的增量。这是您的设置空间

  • Set“S”(预定的分钟数)是该空间的子集
  • 设置“W”,即在作业上花费的时间量,是该空间的子集
“S”和“W”的交叉点是该人员在其计划内的停留时间(以分钟为单位-根据您的需要转换为hh:mm)


使用其他集合算法,您可以找到它们本应存在但不存在的时间,等等。

我会将其视为状态机问题。有四种状态:S+W+,S-W+,S+W-,S-W-。 计划时间对应于S+状态,工人出现在W+状态。目标是将S+W+中的时间添加到交叉口时间

有效的转换是:

S+W+ End of schedule -> S-W+
S+W+ Worker leaves -> S+W-
S-W+ Start of schedule -> S+W+
S-W+ Worker leaves -> S-W-
S+W- End of schedule -> S-W-
S+W- Worker arrives -> S+W+
S-W- Start of schedule -> S+W-
S-W+ Worker arrives -> S-W+
按时间顺序处理事件,从状态S-W-开始。如果两个事件同时发生,则按任意顺序处理


在转换到S+W+时,记下时间。从S+W+过渡时,从过渡时间中减去最后记录的时间,并将结果添加到交叉点时间。

我将把这视为状态机问题。有四种状态:S+W+,S-W+,S+W-,S-W-。 计划时间对应于S+状态,工人出现在W+状态。目标是将S+W+中的时间添加到交叉口时间

有效的转换是:

S+W+ End of schedule -> S-W+
S+W+ Worker leaves -> S+W-
S-W+ Start of schedule -> S+W+
S-W+ Worker leaves -> S-W-
S+W- End of schedule -> S-W-
S+W- Worker arrives -> S+W+
S-W- Start of schedule -> S+W-
S-W+ Worker arrives -> S-W+
按时间顺序处理事件,从状态S-W-开始。如果两个事件同时发生,则按任意顺序处理


在转换到S+W+时,记下时间。从S+W+过渡时,从过渡时间中减去最后一次记录的时间,并将结果添加到交叉点时间。

您可能需要考虑使用,但要小心,它完全忽略了日期时间。Kind,不了解时区,也不尊重夏令时

  • Utc
    种类上使用是安全的
  • 切勿在
    本地
    类型上使用它
  • 如果您在
    未指定的
    种类上使用它,请确保您了解上下文。如果它可能是某个时区中有DST的本地时间,那么您的结果可能是正确的,也可能是不正确的

除此之外,您应该能够使用它的交叉点功能。

您可能想研究一下如何使用它,但要小心,它完全忽略了日期时间。Kind,不知道时区,也不遵守夏令时

  • Utc
    种类上使用是安全的
  • 切勿在
    本地
    类型上使用它
  • 如果您在
    未指定的
    种类上使用它,请确保您了解上下文。如果它可能是某个时区中有DST的本地时间,那么您的结果可能是正确的,也可能是不正确的

除此之外,您应该能够使用它的交集功能。

听起来LINQ应该在这里工作得很好。我举了一个简短的例子,使用我的库,因为它比.NET更好地支持“一天中的时间”,但如果需要,您可以修改它

基本上,你有两个时段集合,你只对交叉点感兴趣——你可以找到任何计划时段与任何移动时段的交叉点——只需使用0长度的时段,就可以很容易地打折不相交的时段

下面是完整的代码,它确实给出了7小时30分钟的总时间:

using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;

class Test
{
    static void Main()
    {
        var schedule = new List<TimePeriod>
        {
            new TimePeriod(new LocalTime(7, 30), new LocalTime(12, 0)),
            new TimePeriod(new LocalTime(13, 30), new LocalTime(17, 0)),
        };

        var movements = new List<TimePeriod>
        {
            new TimePeriod(new LocalTime(6, 50), new LocalTime(6, 55)),
            new TimePeriod(new LocalTime(7, 0), new LocalTime(11, 45)),
            new TimePeriod(new LocalTime(13, 45), new LocalTime(17, 05))
        };

        var durations = from s in schedule
                        from m in movements
                        select s.Intersect(m).Duration;
        var total = durations.Aggregate((current, next) => current + next);
        Console.WriteLine(total);
    }
}

class TimePeriod
{
    private readonly LocalTime start;
    private readonly LocalTime end;

    public TimePeriod(LocalTime start, LocalTime end)
    {
        if (start > end)
        {
            throw new ArgumentOutOfRangeException("end");
        }
        this.start = start;
        this.end = end;
    }

    public LocalTime Start { get { return start; } }
    public LocalTime End { get { return end; } }
    public Duration Duration { get { return Period.Between(start, end)
                                                  .ToDuration(); } }

    public TimePeriod Intersect(TimePeriod other)
    {
        // Take the max of the start-times and the min of the end-times
        LocalTime newStart = start > other.start ? start : other.start;
        LocalTime newEnd = end < other.end ? end : other.end;
        // When the two don't actually intersect, just return an empty period.
        // Otherwise, return the appropriate one.
        if (newEnd < newStart)
        {
            newEnd = newStart;
        }
        return new TimePeriod(newStart, newEnd);
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用NodaTime;
课堂测试
{
静态void Main()
{
var计划=新列表
{
新的时间段(新的本地时间(7,30),新的本地时间(12,0)),
新的时间段(新的本地时间(13,30),新的本地时间(17,0)),
};
var移动=新列表
{
新的时间段(新的本地时间(6,50),新的本地时间(6,55)),
新的时间段(新的本地时间(7,0),新的本地时间(11,45)),
新的时间段(新的本地时间(13,45),新的本地时间(17,05))
};
var持续时间=从计划中的s开始
从我的动作开始
选择s.Intersect(m).持续时间;
var total=持续时间。聚合((当前,下一个)=>当前+下一个);
控制台写入线(总计);
}
}
班级时间段
{
私有只读本地时间启动;
私有只读本地时间结束;
公共时间段(LocalTime开始、LocalTime结束)
{
如果(开始>结束)