2013-02-18 74 views
1

的datesList查询只是一个日期时间值的列表。拆分日期/周列表为a和b周LINQ

随着LINQ查询/ GROUPBY I组所有那些属于某一周在今年进入分组天。

Func<DateTime, int> weekProjector = d => 
CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); 

var weeks = (from date in datesList group date by weekProjector(date.Date)).ToList(); 

让我们假设星期收集包含8,并可以旋转A和B星期。这意味着,如果该用户与周开始通过值2的转动传递该结果:

AA,BB,AA,BB(8周,每周一次旋转是2)

AAAA,BBBB(8周,每周旋转4)

我怎样才能查询周收集和组/项目或任何日期时间值到一个单独weekListA/weekListB用考虑,其可以是从1的任何数量到8

UPDATE旋转值:

最终状态是2个列表A和B列表,每个列表包含周收集的日期时间值。

更新2:在这个样本每周轮换将有因素4:这意味着我有4周A型,4周B型等

enter image description here

+2

我很难理解你的问题。你能否给出一个更完整的例子,说明你希望达到的目标,显示星期的最初状态和最终状态? – 2013-02-18 12:54:56

+3

什么是A周和B周? – 2013-02-18 12:55:16

+0

@Tim当周收集有4周的分组,周旋转值为2时,前2周为A周,最后2周为B周。我认为这从我上面的示例中可以清楚看出。我希望现在清楚:) – Elisabeth 2013-02-18 12:58:07

回答

4

我希望我理解正确你。

给定一串日期,由今年星期分组:

// some testdata 
var datesList = Enumerable.Range(0, 8).Select (e => DateTime.Now.AddDays(7 * e)).ToList(); 

Func<DateTime, int> weekProjector = d => 
    CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); 

var weeks = datesList.GroupBy(weekProjector).ToList(); 

你应该得到你想要通过这个查询结果:

var result = weeks.OrderBy(w => w.Key) 
        .Select((g, i) => new {WeekType = (i/rotation) % 2, Week = g}) 
        .GroupBy(w => w.WeekType) 
        .ToList(); 

其中rotation是你的“旋转” (24)和2是要(组AB => 2基团)基团的数目。

您可能要添加到SelectGroupBy后,只选择你想要的数据,例如:

var weekA = result.Where(r => r.Key==0).Select(g => g).SelectMany(g => g).SelectMany(a => a.Week).ToList(); 
var weekB = result.Where(r => r.Key==1).Select(g => g).SelectMany(g => g).SelectMany(a => a.Week).ToList(); 

更可读/通用的解决方案:

void Rotate<TResult, TGroup>(IEnumerable<TResult> datesList, Func<TResult, TGroup> grouper, int rotation, out List<TResult> listA, out List<TResult> listB) 
{ 
    listA = new List<TResult>(); 
    listB = new List<TResult>(); 

    var weeks = datesList.GroupBy(grouper).ToList(); 

    var c_rotation = 0; 
    var c_list = listA; 

    using (var en = weeks.GetEnumerator()) 
     while(en.MoveNext()) 
     { 
      c_list.AddRange((IGrouping<TGroup, TResult>)en.Current); 
      c_rotation++; 
      if (c_rotation == rotation) 
      { 
       c_rotation = 0; 
       c_list = c_list == listA ? listB : listA; 
      } 
     } 
} 

使用它喜欢:

List<DateTime> listA; 
List<DateTime> listB; 

Func<DateTime, int> weekProjector = d => 
    CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(d, CalendarWeekRule.FirstDay, DayOfWeek.Monday); 

Rotate(datesList, weekProjector, 2, out listA, out listB); 
+0

在我测试了Tim的代码之后,我测试了你的代码,并且它与旋转2和4一起工作,所以我应该假设也可以和6和8一起工作。祝贺!并感谢你。因为这也是关于学习的,你认为带索引/旋转的SkipWhile在这里也可以有帮助吗? – Elisabeth 2013-02-18 14:25:58

+0

@Elisa很高兴我能帮到你。请考虑投票:-)我不认为'SkipWhile'适合这里,因为它的目的是跳过一些项目,并返回其余的。 – sloth 2013-02-18 14:41:08

+0

那么跳过就是跳过B周的索引0和1,跳过2周和3周。我不会说它不适合。但是,我是upvoted你知道:) – Elisabeth 2013-02-18 14:48:22

1

这可能是什么你要找的,GroupBy Index % 2

var abRotations = datesList 
    .GroupBy(d => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(d, CalendarWeekRule.FirstDay, DayOfWeek.Monday)) 
    .Select((wg, i) => new { WeekGroup = wg, Index = i }) 
    .GroupBy(x => x.Index % 2); 

List<DateTime> A_Rotation = abRotations.First().SelectMany(x => x.WeekGroup).ToList(); 
List<DateTime> B_Rotation = abRotations.Last().SelectMany(x => x.WeekGroup).ToList(); 

DEMO

+0

groupby索引模块2有趣。我想到了SkipeWhile,并以某种方式考虑了轮换的索引。 – Elisabeth 2013-02-18 13:29:13

+0

我测试了您的代码,并且与我的期望不同。我将通过深入的示例来更新输出结果。我还以为你会用我的周收藏作为出发点。我猜你以某种方式确定了索引%2的旋转吗? – Elisabeth 2013-02-18 13:41:14

+0

@Elisa:也许我误解了这个要求。发布一个完整的'DateTime'的初始化列表和所需的结果。我的想法是首先将所有日期分组。然后将这些组分成两个子组“A_Rotation”+“B_Rotation”。最后的结果是这两个组的“List ”,因为你提到过:_“最终状态是2个列表A和B列表,每个列表都包含来自周收集的日期时间值。”# – 2013-02-18 13:47:11

相关问题