按行动分组并获得正确的权利

时间:2017-09-15 08:10:31

标签: c# linq datetime grouping

我有一个List ActionSchedule

public class ActionSchedule
{
    public TaskJob Mode {get;set}
    public TimeSpan Start {get;set}

    public DateTime ConvertToDatime(bool updatenextday = false)
    {
        DateTime result = DateTime.Today.Add(Start);

        if (updatenextday)
        {
            if (Start.Hours < dateTimeNow.Hour || (Start.Hours == dateTimeNow.Hour && Start.Minutes <= dateTimeNow.Minute))
                result = result.AddDays(1);
        }

        return result;
    }

} 

public enum TaskJob
    {
        Pause,
        Resume,
        Login,
        Close,
    }

示例列表:

GR1

登录9:00 暂停9:02 10:00恢复 关闭15:00

GR2

登录17:00 暂停18:00 18:30恢复 关闭21:00

GR3

登录22:00 关闭06:00(第二天)

我需要从此列表中获取以Mode =登录广告开头的操作以Mode = Close和模式登录的开始(TimeSpan)&gt; time.now和模式开始关闭&lt;现在是时候了。

如果datetime现在是10:00,它会给我gr1列表

如果datetime现在是14:00,它会给我gr1列表

如果datetime现在是16:00,它会给我gr2 list导致gr1在15:00结束

如果datetime现在是20:00,它会给我gr2

如果datetime现在是23:00,它会给我gr3

如果datetime现在是05:00,它会给我gr3

如果datetime现在是07:00它会给我gr1因为gr3在06:00结束

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

您的要求不清楚,但我会尝试推断。

上下文

你有List<ActionSchedule>

var actions = new List<ActionSchedule>
{
    new ActionSchedule { Mode = TaskJob.Login, Start = new TimeSpan(9,0,0) },
    new ActionSchedule { Mode = TaskJob.Pause, Start = new TimeSpan(9,2,0) },
    new ActionSchedule { Mode = TaskJob.Resume, Start = new TimeSpan(10,0,0) },
    new ActionSchedule { Mode = TaskJob.Close, Start = new TimeSpan(15,0,0) },
    new ActionSchedule { Mode = TaskJob.Login, Start = new TimeSpan(17,0,0) },
    new ActionSchedule { Mode = TaskJob.Pause, Start = new TimeSpan(18,0,0) },
    new ActionSchedule { Mode = TaskJob.Resume, Start = new TimeSpan(18,30,0) },
    new ActionSchedule { Mode = TaskJob.Close, Start = new TimeSpan(21,0,0) },
    new ActionSchedule { Mode = TaskJob.Login, Start = new TimeSpan(22,0,0) },
    new ActionSchedule { Mode = TaskJob.Close, Start = new TimeSpan(6,0,0) }
};

您需要List<List<ActionSchedule>>(或类似List<ActionScheduleCollection>之类的内容),以便您可以拥有&#34;群组&#34;,让我们将其命名为actionLists。它将包含您的所有ActionSchedule,分为列表(&#34;群组&#34;),以Login ActionSchedule开头,以Close结尾。实施是微不足道的:

var actionLists = new List<List<ActionSchedule>>();
List<ActionSchedule> actionList = null;
foreach (var action in actions)
{
    if (action.Mode == TaskJob.Login)
    {
        actionList = new List<ActionSchedule>();
        actionLists.Add(actionList);
    }

    actionList.Add(action);
}

要求

你想要当前&#34;活跃&#34;组(DateTime.Now介于&#34;活动&#34;组的登录和关闭时间),或者将是&#34;活跃&#34;下。

  

如果datetime现在是14:00,它会给我gr1列表

     

如果datetime现在是16:00,它会给我gr2列表导致gr1结束于15:00 (注意:即使gr2从17:00开始)

解决方案

这比我想象的要复杂得多!还有这样一个不方便的ActionSchedule结构。

基本上,我们会进行两步验证以获取当前组。 首先,我们天真地检查一个群组的登录时间是否小于当前时间,并且关闭时间大于当前时间。 如果没有,我们遍历各组,比较每个组,并找到关闭时间小于当前时间的组,以及下一组的登录时间比当前时间更好。

这有点沙拉,所以这里有一些代码:

private static List<ActionSchedule> GetCurrentGroup(List<List<ActionSchedule>> actionLists, TimeSpan now)
{
    var currentGroup = actionLists.SingleOrDefault(actionList => IsActive(actionList, now));

    if (currentGroup == null)
    {
        // Comparing each list with the next to see where 'now' fits for the 'next active group'
        // We assume lists are already ordered by their start time, and that their start/close times
        // don't overlap
        for (int i = 0; i < actionLists.Count; i++)
        {
            // index of the next list; if it's out of bounds, we reset to the first list, index 0
            int j = i + 1;
            if (j >= actionLists.Count)
                j = 0;

            var nextList = actionLists[j];

            var closeFirst = actionLists[i].Single(action => action.Mode == TaskJob.Close).Start;
            var loginLast = nextList.Single(action => action.Mode == TaskJob.Login).Start;

            if (TimeBetween(now, closeFirst, loginLast))
            {
                currentGroup = nextList;
                break;
            }
        }
    }

    return currentGroup;
}

private static bool IsActive(List<ActionSchedule> actionList, TimeSpan now)
{
    var login = actionList.Single(action => action.Mode == TaskJob.Login).Start;
    var close = actionList.Single(action => action.Mode == TaskJob.Close).Start;
    return TimeBetween(now, login, close);
}

private static bool TimeBetween(TimeSpan now, TimeSpan start, TimeSpan end)
{
    if (start < end)
        return start <= now && now <= end;
    return !(end < now && now < start);
}

测试

static void Main(string[] args)
{
    var actions = new List<ActionSchedule>
    {
        new ActionSchedule { Mode = TaskJob.Login, Start = new TimeSpan(9,0,0) },
        new ActionSchedule { Mode = TaskJob.Pause, Start = new TimeSpan(9,2,0) },
        new ActionSchedule { Mode = TaskJob.Resume, Start = new TimeSpan(10,0,0) },
        new ActionSchedule { Mode = TaskJob.Close, Start = new TimeSpan(15,0,0) },
        new ActionSchedule { Mode = TaskJob.Login, Start = new TimeSpan(17,0,0) },
        new ActionSchedule { Mode = TaskJob.Pause, Start = new TimeSpan(18,0,0) },
        new ActionSchedule { Mode = TaskJob.Resume, Start = new TimeSpan(18,30,0) },
        new ActionSchedule { Mode = TaskJob.Close, Start = new TimeSpan(21,0,0) },
        new ActionSchedule { Mode = TaskJob.Login, Start = new TimeSpan(22,0,0) },
        new ActionSchedule { Mode = TaskJob.Close, Start = new TimeSpan(6,0,0) }
    };

    var actionLists = new List<List<ActionSchedule>>();
    List<ActionSchedule> actionList = null;
    foreach (var action in actions)
    {
        if (action.Mode == TaskJob.Login)
        {
            actionList = new List<ActionSchedule>();
            actionLists.Add(actionList);
        }

        actionList.Add(action);
    }

    Console.WriteLine("Time is 10:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(10, 0, 0)));

    Console.WriteLine("Time is 14:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(14, 0, 0)));

    Console.WriteLine("Time is 16:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(16, 0, 0)));

    Console.WriteLine("Time is 20:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(20, 0, 0)));

    Console.WriteLine("Time is 23:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(23, 0, 0)));

    Console.WriteLine("Time is 05:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(5, 0, 0)));

    Console.WriteLine("Time is 07:00:00");
    PrintGroup(GetCurrentGroup(actionLists, new TimeSpan(7, 0, 0)));

    Console.ReadLine();
}

private static void PrintGroup(List<ActionSchedule> group)
{
    Console.WriteLine($"Login: {group.Single(a => a.Mode == TaskJob.Login).Start}, Closing: {group.Single(a => a.Mode == TaskJob.Close).Start}");
}