繁体   English   中英

两组数据的交集

[英]intersection of two sets of data

在过去的一个半星期中,我一直在努力研究这种算法,但我无法使其正常工作。

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

你有什么建议吗? 我可以在这里应用的数学理论或规则? 或您看到的类似问题可以指出我的观点? 我一直很难找到解决方案。 任何帮助,将不胜感激。

图片

例如:

时间表:
上午7:30(开始)12:00 pm(午餐)
1:30 pm(endLunchBreak)5:00 pm(endOfWorkday)

一天中人们的动向:
进:6:50 am,出:6:55 am
进:7:00 am,出:11:45 am
进:1:45 pm,出:5:05 pm

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

我将其视为状态机问题。 有四种状态:S + W +,S-W +,S + W-,SW-。 计划的时间对应于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+

从状态SW-开始按时间顺序处理事件。 如果两个事件同时发生,则以任一顺序处理。

过渡到S + W +时,请注意时间。 从S + W +过渡出来时,从过渡时间中减去最后记下的时间,并将结果加到相交时间上。

以1分钟为增量将天数分成1440。 这是您设置的空间。

  • 设置的分钟数“ S”是该空间的子集。
  • 设置“ W”(花费在工作上的时间)是该空间的子集。

“ S”和“ W”的交集是该人在时间表内到场的时间(以分钟为单位-根据您的需要转换为hh:mm)。

使用其他集合算法,您可以找到它们何时应到达但未到达的时间,等等。

您可能想研究使用此库 ,但请注意,它完全忽略了DateTime.Kind ,它不识别时区,也不尊重夏时制。

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

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

听起来LINQ在这里应该可以正常工作。 我举了一个简短的示例,使用我的Noda Time库,因为它比.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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM