2011-10-18 3 views
1

1ヶ月(開始日と終了日として定義)をとり、その月の各週の日付範囲のセットを返す必要があります。 1週間は、日曜日から土曜日までを定義します。 10/1〜10/1、10/2:これは、ある月に毎週見つけるのに適したアルゴリズムですか?

http://i54.tinypic.com/j58sh0.png

2011年10月の月の6週間を持っている:スタートバーで、Windowsの日にあなたをダブルクリックがあれば、それを視覚化するための良い方法です10/8,10/9-10/15,10/16-10/22,10/23-10/29および10/30-10/31である。

私は、構造体として毎週記述することができます。

struct Range 
    { 
     public DateTime Start; 
     public DateTime End; 

     public Range(DateTime start, DateTime end) 
     { 
     Start = start; 
     End = end; 
     } 
    } 

私は月を取り、その中の範囲の配列を返す関数を記述する必要があります。ここで動作するように表示され、明白なエッジケースに対処し、私の最初の試みは、です:

public static IEnumerable<Range> GetRange(DateTime start, DateTime end) 
{ 
    DateTime curStart = start; 
    DateTime curPtr = start; 
    do 
    { 
     if (curPtr.DayOfWeek == DayOfWeek.Saturday) 
     { 
     yield return new Range(curStart, curPtr); 
     curStart = curPtr.AddDays(1); 
     } 

     curPtr = curPtr.AddDays(1); 
    } while (curPtr <= end); 

    if(curStart <= end) 
     yield return new Range(curStart, end); 
} 

私は同じことを行うにはクリーナー以上の明白なアプローチがありますかどうかを知りたいと思います。私はパフォーマンスについて心配していませんが、コードの読みやすさを向上させ、アルゴリズムをより簡潔にしたいと思います。おそらく、単一のLINQ式などを含む非常に創造的なソリューションがあります。ありがとう!

+0

http://codereview.stackexchange.com/ –

+3

:-)実行されません、ToListまたはToArrayを使用して結果を「実体化」することを忘れないでくださいサイドノート:もしあなたが国際的に行く予定があるなら、日曜日に始まる週を定義することはできません! –

+0

ありがとう!私はそのサイトを知らなかった。 –

答えて

1

Previtiの示唆しているように、これは単に国際的に使用できるように、7ずつインクリメントしています。あなたのC#は< 4.0であれば、= DayOfWeek.Sunday

public static IEnumerable<Range> GetRange(DateTime start, DateTime end, DayOfWeek startOfTheWeek = DayOfWeek.Sunday) 
{ 
    if (start > end) 
    { 
     throw new ArgumentException(); 
    } 

    // We "round" the dates to the beginning of the day each 
    start = start.Date; 
    end = end.Date; 

    // The first week. It could be "shorter" than normal. We return it "manually" here 
    // The 6 + startOfWeek - start.DayOfWeek will give us the number of days that you 
    // have to add to complete the week. It's mod 7. It's based on the idea that 
    // the starting day of the week is a parameter. 
    DateTime curDay = new DateTime(Math.Min(start.AddDays((6 + (int)startOfTheWeek - (int)start.DayOfWeek) % 7).Ticks, end.Ticks), start.Kind); 

    yield return new Range(start, curDay); 

    curDay = curDay.AddDays(1); 

    while (curDay <= end) 
    { 
     // Each time we add 7 (SIX) days. This is because the difference between 
     // as considered by the problem, it's only 6 * 24 hours (because the week 
     // doesn't end at 23:59:59 of the last day, but at the beginning of that day) 
     DateTime nextDay = new DateTime(Math.Min(curDay.AddDays(6).Ticks, end.Ticks), start.Kind); 

     yield return new Range(curDay, nextDay); 

     // The start of the next week 
     curDay = nextDay.AddDays(1); 
    } 
} 

いくつかの小さなノートデフォルトのパラメータを削除:Math.MinDateTimeために定義されたので、私はDateTime秒のTicksを取り、それらを比較することによって、少しカンニングされていません。その後、DateTimeを再構築します。私はいつもstartDateTimeKindを使用しています。あなたがyieldコードをデバッグするとき

、それ以外のコードは

+0

恐ろしい!これは素晴らしいアプローチです。 –

+0

@MikeChristensenもっと読みやすいようにいくつかのコメントを追加しました。 – xanatos

関連する問題