2013-03-14 29 views
13

日付。グループ連続は私が持っているクラスを持っている<code>List<DateTime> dates;</code></p> <p>を持って

public List<NonWorkingDay> GetContiguousDates(List<DateTime> dates) 
{ 

} 

注:金曜日にNWDがあり、次は月曜日がある場合は、グループ化する必要があります。週末は考慮されません。例えば

私は

September 3 2013 
September 20 2013 
September 23 2013 
September 24 2013 
September 30 2013 
October 1 2013 

を持っている場合、出力は次のようになります。

Start = September 3 2013, Days = 1 
Start = September 20 2013, Days = 3 //weekend got skipped 
Start = September 30 2013, Days = 2 

これを行うにはどのような方法は、(カウンタ変数の束を持っていない)があり、.Selectまたはを使用して。どこか何か。

おかげ

+4

素敵なパズル!... – spender

+0

グループの週にしてグループ内のアイテムを数えてください。週ごとのグループ分けはこちらhttp://stackoverflow.com/questions/8561782/how-to-group-dates-by-week – bUKaneer

+0

いいえ、そこに月曜日金曜日の2.5週間を言うかもしれないので、 – jmasterx

答えて

17

だから、我々はこの一般的なイテレータ機能から始めましょう。これは、2つの項目を受け入れてブール値を返すシーケンスと述語を取ります。それはソースから項目を読み込み、項目はその前の項目とともに述語に基づいて真を返し、次の項目は「次のグループ」になります。 falseを返すと、前のグループはいっぱいになり、次のグループが開始されます。

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> source 
    , Func<T, T, bool> predicate) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
      yield break; 

     List<T> currentGroup = new List<T>() { iterator.Current }; 
     while (iterator.MoveNext()) 
     { 
      if (predicate(currentGroup.Last(), iterator.Current)) 
       currentGroup.Add(iterator.Current); 
      else 
      { 
       yield return currentGroup; 
       currentGroup = new List<T>() { iterator.Current }; 
      } 
     } 
     yield return currentGroup; 
    } 
} 

また、日付に基づいて翌営業日を取得するこの簡単なヘルパーメソッドも必要です。休日を組み入れたい場合は、それは簡単なものから非常に難しいものへと変わりますが、それは論理がどこに行くのかです。

public static DateTime GetNextWorkDay(DateTime date) 
{ 
    DateTime next = date.AddDays(1); 
    if (next.DayOfWeek == DayOfWeek.Saturday) 
     return next.AddDays(2); 
    else if (next.DayOfWeek == DayOfWeek.Sunday) 
     return next.AddDays(1); 
    else 
     return next; 
} 

ここでまとめておきます。まず、私たちは日を注文します。 (もし彼らがいつも来てくれたら、あなたはその部分を取り除くことができます。)そして、私たちは各項目が前の仕事の次の日である間、連続する項目をグループ化します。

次に、NonWorkingDayに連続する日付のIEnumerable<DateTime>を設定するだけです。そのため、開始日は最初の日付であり、Daysはシーケンスのカウントです。通常FirstCountの両方を使用すると、元のシーケンスが2回繰り返されるため、GroupWhileによって返されるシーケンスは実際にはListですが、複数回反復することは問題ではなく、Countは偶数です1)。

public IEnumerable<NonWorkingDay> GetContiguousDates(IEnumerable<DateTime> dates) 
{ 
    return dates.OrderBy(d => d) 
      .GroupWhile((previous, next) => GetNextWorkDay(previous).Date == next.Date) 
      .Select(group => new NonWorkingDay 
       { 
        Start = group.First(), 
        Days = group.Count(), 
       }); 
} 
+5

絶対天才、よくやった! ; o) – bUKaneer

+0

@plutonixいくつかはすぐにはっきりしないかもしれませんが、この場合は実質的にコピー/ペーストしています... – Servy

関連する問題