2013-02-18 80 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

相關問題