簡體   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