[英]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”的交集是该人在时间表内到场的时间(以分钟为单位-根据您的需要转换为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.