我正在尝试选择列表的子组,其中项目具有连续的日期,例如
ID StaffID Title ActivityDate -- ------- ----------------- ------------ 1 41 Meeting with John 03/06/2010 2 41 Meeting with John 08/06/2010 3 41 Meeting Continues 09/06/2010 4 41 Meeting Continues 10/06/2010 5 41 Meeting with Kay 14/06/2010 6 41 Meeting Continues 15/06/2010
我每次都使用一个轴心点,所以将示例枢轴项目设为3,我想在枢轴周围得到以下产生的连续事件:
ID StaffID Title ActivityDate -- ------- ----------------- ------------ 2 41 Meeting with John 08/06/2010 3 41 Meeting Continues 09/06/2010 4 41 Meeting Continues 10/06/2010
我目前的实施是一个艰难的"走"过去,然后到未来,建立列表:
var activity = // item number 3: Meeting Continues (09/06/2010)
var orderedEvents = activities.OrderBy(a => a.ActivityDate).ToArray();
// Walk into the past until a gap is found
var preceedingEvents = orderedEvents.TakeWhile(a => a.ID != activity.ID);
DateTime dayBefore;
var previousEvent = activity;
while (previousEvent != null)
{
dayBefore = previousEvent.ActivityDate.AddDays(-1).Date;
previousEvent = preceedingEvents.TakeWhile(a => a.ID != previousEvent.ID).LastOrDefault();
if (previousEvent != null)
{
if (previousEvent.ActivityDate.Date == dayBefore)
relatedActivities.Insert(0, previousEvent);
else
previousEvent = null;
}
}
// Walk into the future until a gap is found
var followingEvents = orderedEvents.SkipWhile(a => a.ID != activity.ID);
DateTime dayAfter;
var nextEvent = activity;
while (nextEvent != null)
{
dayAfter = nextEvent.ActivityDate.AddDays(1).Date;
nextEvent = followingEvents.SkipWhile(a => a.ID != nextEvent.ID).Skip(1).FirstOrDefault();
if (nextEvent != null)
{
if (nextEvent.ActivityDate.Date == dayAfter)
relatedActivities.Add(nextEvent);
else
nextEvent = null;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,列表relatedActivities应按顺序包含连续事件.
有更好的方法(也许使用LINQ)吗?
我有一个使用的想法,.Aggregate()但是当它找到序列中的间隙时,无法想到如何使聚合突破.
这是一个实现:
public static IEnumerable<IGrouping<int, T>> GroupByContiguous(
this IEnumerable<T> source,
Func<T, int> keySelector
)
{
int keyGroup = Int32.MinValue;
int currentGroupValue = Int32.MinValue;
return source
.Select(t => new {obj = t, key = keySelector(t))
.OrderBy(x => x.key)
.GroupBy(x => {
if (currentGroupValue + 1 < x.key)
{
keyGroup = x.key;
}
currentGroupValue = x.key;
return keyGroup;
}, x => x.obj);
}
Run Code Online (Sandbox Code Playgroud)
您可以通过减法将日期转换为整数,或者想象一下DateTime版本(轻松).
在这种情况下,我认为标准foreach循环可能比 LINQ 查询更具可读性:
var relatedActivities = new List<TActivity>();
bool found = false;
foreach (var item in activities.OrderBy(a => a.ActivityDate))
{
int count = relatedActivities.Count;
if ((count > 0) && (relatedActivities[count - 1].ActivityDate.Date.AddDays(1) != item.ActivityDate.Date))
{
if (found)
break;
relatedActivities.Clear();
}
relatedActivities.Add(item);
if (item.ID == activity.ID)
found = true;
}
if (!found)
relatedActivities.Clear();
Run Code Online (Sandbox Code Playgroud)
就其价值而言,这里有一个大致相同但可读性差得多的 LINQ 查询:
var relatedActivities = activities
.OrderBy(x => x.ActivityDate)
.Aggregate
(
new { List = new List<TActivity>(), Found = false, ShortCircuit = false },
(a, x) =>
{
if (a.ShortCircuit)
return a;
int count = a.List.Count;
if ((count > 0) && (a.List[count - 1].ActivityDate.Date.AddDays(1) != x.ActivityDate.Date))
{
if (a.Found)
return new { a.List, a.Found, ShortCircuit = true };
a.List.Clear();
}
a.List.Add(x);
return new { a.List, Found = a.Found || (x.ID == activity.ID), a.ShortCircuit };
},
a => a.Found ? a.List : new List<TActivity>()
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2405 次 |
| 最近记录: |