使用 Linq 查找一组常见对象
Using Linq to find a group of common objects
我想做的是,如果您查看下面的代码,请编写一个 Linq 语句,该语句将 return ShiftEvent 组。一个组由 1.) EmpId, 2.) EndDate/Time of one ShiftEvent = StartDate/Time of one ShiftEvent
然后我想创建一个 Shift 对象,我将 ShiftEvent 组放在 Shift.List 中。
我写了一个半吊子的 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);
}
}
任何指点都很棒!
您可以先按员工对轮班事件进行分组:
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 }
};
}
}
我忽略了 Shift
和 class 中的 StartOfShitTime
& EndOfShiftTime
属性,因为 StartOfShiftDate
& EndOfShiftDate
足以存储时间信息。
此解决方案还假设轮班事件时间没有重叠。
我想做的是,如果您查看下面的代码,请编写一个 Linq 语句,该语句将 return ShiftEvent 组。一个组由 1.) EmpId, 2.) EndDate/Time of one ShiftEvent = StartDate/Time of one ShiftEvent
然后我想创建一个 Shift 对象,我将 ShiftEvent 组放在 Shift.List
我写了一个半吊子的 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);
}
}
任何指点都很棒!
您可以先按员工对轮班事件进行分组:
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 }
};
}
}
我忽略了 Shift
和 class 中的 StartOfShitTime
& EndOfShiftTime
属性,因为 StartOfShiftDate
& EndOfShiftDate
足以存储时间信息。
此解决方案还假设轮班事件时间没有重叠。