使用Linq查找一组常用对象

时间:2015-01-25 21:01:52

标签: c# linq

我想要做的是,如果你在代码中看下面,写一个Linq语句,它将返回ShiftEvents组。组由1.)EmpId定义,2。)EndDate /一个ShiftEvent的时间= StartDate /下一个ShiftEvent的时间

我想创建一个Shift对象,我将ShiftEvents组放在Shift.List< ShiftEvents>。

我有一半写了Linq语句似乎加入了ShiftEvents ..这是我完全失去的分组部分。

class ShiftEvent{
    public int EmpId { get; set; }
    public string Activity { get; set; }
    public string StartDate { get; set; }
    public string StartTime { get; set; }
    public string EndDate { get; set; }
    public string EndTime { get; set; }
}

class Shift{
    public List<ShiftEvent> ShiftEvents { get; set; }
    public int EmployeeId { get; set; }
    public DateTime StartOfShiftDate { get; set; }
    public DateTime StartOfShiftTime { get; set; }
    public DateTime EndOfShiftDate { get; set; }
    public DateTime EndOfShiftTime { get; set; }
}

void Main()
{
    List<ShiftEvent> se = new List<ShiftEvent>();
    // Group 1
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/21", StartTime="23:00",EndDate="2015/01/21",EndTime="23:30"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/21", StartTime="23:30",EndDate="2015/01/22",EndTime="00:30"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="00:30",EndDate="2015/01/22",EndTime="05:30"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="05:30",EndDate="2015/01/22",EndTime="06:30"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="06:30",EndDate="2015/01/22",EndTime="07:00"});
    // Group 2
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="07:15",EndDate="2015/01/22",EndTime="09:00"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="09:00",EndDate="2015/01/22",EndTime="10:00"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="10:00",EndDate="2015/01/22",EndTime="11:00"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="11:00",EndDate="2015/01/22",EndTime="12:00"});
    se.Add(new ShiftEvent {EmpId=1, Activity="Test", StartDate="2015/01/22", StartTime="12:00",EndDate="2015/01/22",EndTime="13:00"});
    // Group 3
    se.Add(new ShiftEvent {EmpId=2, Activity="Test", StartDate="2015/01/22", StartTime="07:15",EndDate="2015/01/22",EndTime="09:00"});
    se.Add(new ShiftEvent {EmpId=2, Activity="Test", StartDate="2015/01/22", StartTime="09:00",EndDate="2015/01/22",EndTime="10:00"});
    se.Add(new ShiftEvent {EmpId=2, Activity="Test", StartDate="2015/01/22", StartTime="10:00",EndDate="2015/01/22",EndTime="11:00"});
    se.Add(new ShiftEvent {EmpId=2, Activity="Test", StartDate="2015/01/22", StartTime="11:00",EndDate="2015/01/22",EndTime="12:00"});
    se.Add(new ShiftEvent {EmpId=2, Activity="Test", StartDate="2015/01/22", StartTime="12:00",EndDate="2015/01/22",EndTime="13:00"});


    var obj = from s1 in se
            join s2 in se
                on new {EmpId = s1.EmpId, Date = s1.EndDate, Time = s1.EndTime} equals new {EmpId = s2.EmpId, Date=s2.StartDate, Time = s2.StartTime}
            select s1;

    var shiftList = new List<Shift>();

    foreach(var shiftEvent in obj){
        var shift = new Shift();
        shift.ShiftEvent.Add(shiftEvent);
        shift.EmployeeId = shiftEvent.EmpId;
        .......
        shiftList.Add(shift);
    }


}

任何指针都会很棒!

1 个答案:

答案 0 :(得分:2)

您可以从员工对班次事件进行分组开始:

var employeeShifts = _shiftEvents.GroupBy(item => item.EmpId);

然后迭代它们以创建轮班。使用第一个班次事件创建第一个班次。如果下一个班次事件在最后一个班次结束时开始,则更新班次的结束日期。如果存在间隙,请将班次添加到列表中并使用当前班次开始新班次。

这是整个解决方案。它有点乱,因为你把时间信息保存为字符串。

var employeeShifts = _shiftEvents.GroupBy(item => item.EmpId);

List<Shift> shifts = new List<Shift>();
foreach (IGrouping<int, ShiftEvent> employeeShift in employeeShifts)
{
    var orderedShiftEvents = employeeShift.Select(item => new { ShiftEvent = item, Interval = item.GetShiftInterval() })
                                          .OrderBy(item => item.Interval.Item1);

    Shift currentShift = null;
    foreach (var shiftEvent in orderedShiftEvents)
    {
        if (currentShift == null)
        {
            currentShift = shiftEvent.ShiftEvent.StartShift(shiftEvent.Interval);
            continue;
        }

        if (currentShift.EndOfShiftDate == shiftEvent.Interval.Item1)
        {
            currentShift.EndOfShiftDate = shiftEvent.Interval.Item2;
            currentShift.ShiftEvents.Add(shiftEvent.ShiftEvent);
        }
        else
        {
            shifts.Add(currentShift);
            currentShift = shiftEvent.ShiftEvent.StartShift(shiftEvent.Interval);
        }
    }
    shifts.Add(currentShift);
}

我必须使用的扩展方法:

public static class ShiftEventExtensions
{
    public static Tuple<DateTime, DateTime> GetShiftInterval(this ShiftEvent shiftEvent)
    {
        return new Tuple<DateTime, DateTime>(ParseDateTime(shiftEvent.StartDate, shiftEvent.StartTime), ParseDateTime(shiftEvent.EndDate, shiftEvent.EndTime));
    }

    private static DateTime ParseDateTime(string date, string time)
    {
        string text = string.Concat(date, " ", time);
        DateTime result;

        if (DateTime.TryParse(text, out result))
        {
            return result;
        }

        throw new ArgumentException("Invalid DateTime", text);
    }

    public static Shift StartShift(this ShiftEvent shiftEvent, Tuple<DateTime, DateTime> interval)
    {
        return new Shift
        {
            EmployeeId = shiftEvent.EmpId,
            StartOfShiftDate = interval.Item1,
            EndOfShiftDate = interval.Item2,
            ShiftEvents = new List<ShiftEvent> { shiftEvent }
        };
    }
}

我忽略了StartOfShitTime&amp; EndOfShiftTimeShift中的StartOfShiftDate属性,因为EndOfShiftDate&amp; {{1}}足以存储时间信息。

此解决方案还假设班次事件时间没有重叠。