5

すべての日付が「月の最初の月曜日」であるという意味で、1 か月離れている日付のリストがあります。場合によっては月が欠落しているため、すべての日付が連続しているかどうかを判断する関数を作成する必要があります

たとえば、これが日付のリストである場合、すべての項目が「月の最初の金曜日」であり、ギャップがないため、関数は true を返します。以下の例は true を返します。

 var date = new DateTime(2013, 1, 4);
 var date1 = new DateTime(2013, 2, 1);
 var date2 = new DateTime(2013, 3, 1);
 var date3 = new DateTime(2013, 4, 5);

 var dateArray = new DateTime[]{date, date1, date2, date3};
 bool isConsecutive = IsThisListConsecutive(dateArray);

以下の例では false が返されます。これらはすべて「月の最初の金曜日」でもありますが、2013 年 3 月の項目がないためです。

 var date = new DateTime(2013, 1, 4);
 var date1 = new DateTime(2013, 2, 1);
 var date3 = new DateTime(2013, 4, 5);

 var dateArray = new DateTime[]{date, date1, date3};
 bool isConsecutive = IsThisListConsecutive(dateArray);

だから私は IsThisListConsecutive() メソッドの正しいロジックを理解しようとしています:

これが私の最初の試みでした:(すべての日付が同じ曜日と同じ月の週であることを前もって知っているので、探しているのは欠落しているスロットだけです)

  private bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
    {
        DateTime firstDate = orderedSlots.First();
        int count = 0;
        foreach (var slot in orderedSlots)
        {
            if (slot.Month != firstDate.AddMonths(count).Month)
            {
                return false;
            }
            count++;
        }
        return true;
    }

上記のコードは、リストがある年から別の年にまたがる場合を除いて機能します。この関数を作成するためのより良い方法と、何年にもわたる日付を処理するためにその行を書き直す方法についてアドバイスを求めたいと思いました。

4

6 に答える 6

3

したがって、これを実装するには、シーケンスを受け取り、各アイテムとその前のアイテムを構成するペアのシーケンスを返す単純なヘルパー メソッドから始めます。

public static IEnumerable<Tuple<T, T>> Pair<T>(this IEnumerable<T> source)
{
    T previous;
    using (var iterator = source.GetEnumerator())
    {
        if (iterator.MoveNext())
            previous = iterator.Current;
        else
            yield break;

        while(iterator.MoveNext())
        {
            yield return Tuple.Create(previous, iterator.Current);
            previous = iterator.Current;
        }
    }
}

また、この単純な方法を使用して、2 つの日付が同じ月にあるかどうかを判断します。

public static bool AreSameMonth(DateTime first, DateTime second)
{
    return first.Year == second.Year 
        && first.Month == second.Month;
}

これを使用して、各日付の月を簡単に取得し、前の月の次の月かどうかを確認できます。すべてのペアに当てはまる場合、連続した月があります。

private static bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
    return orderedSlots.Pair()
        .All(pair => AreSameMonth(pair.Item1.AddMonths(1), pair.Item2));
}
于 2013-03-11T16:48:13.183 に答える
2

さて、1月1日はある年の月曜日と次の火曜日になる可能性があるため、年が交差するときにコードは機能しません。私がこれをしているなら、私は最初にそれをチェックします

a)毎月同じ曜日です(DateTime.DayOfWeekを使用)

b)各月の同じ週です*拡張メソッドDayOfMonthを使用します(リンクを参照)* .NETで月の週を計算します*

(あなたはすでにa&bが真であることを知っていると言ったので、3番目の条件に進みましょう)

c)それらが連続した月にあるかどうかを判断する必要があります

//order the list of dates & place it into an array for ease of looping
DateTime[] orderedSlots = slots.OrderBy( t => t).ToArray<DateTime>();


//create a variable to hold the date from the previous month
DateTime temp = orderedSlots[0];


for(i= 1; index < orderedSlots.Length; index++)
{
    if((orderedSlots[index].Month != temp.AddMonths(1).Month |
        orderedSlots[index].Year  != temp.AddMonths(1).Year)){
        return false;
    }

    previousDate =  orderedSlots[index];
}

return true;

条件aとbを確認する必要がある場合は、次のようにifステートメントを変更して追加します。

    if( orderedSlots[index].Month != temp.AddMonths(1).Month |
        orderedSlots[index].Year  != temp.AddMonths(1).Year) |
        orderedSlots[index].DayOfWeek != temp.DayOfWeek      |
        orderedSlots[index].GetWeekOfMonth != temp.AddMonths(1).GetWeekOfMonth){
        return false;
    }

月の週を取得する拡張メソッドを使用するには、.NETの月の週の計算にコードを含める必要があることを覚えておいてください 。テキストエディタでこれを行ったのと同じように、タイプミスがあるはずです。

于 2013-03-11T02:19:03.933 に答える
2

注:これは完全にテストされておらず、日付チェックはおそらくかなり悪いか、やや冗長ですが、それは私が今思いつくことができる最高のものです^^

public bool AreSameWeekdayEveryMonth(IEnumerable<DateTime> dates)
{
    var en = dates.GetEnumerator();
    if (en.MoveNext())
    {
        DayOfWeek weekday = en.Current.DayOfWeek;
        DateTime previous = en.Current;
        while (en.MoveNext())
        {
            DateTime d = en.Current;
            if (d.DayOfWeek != weekday || d.Day > 7)
                return false;
            if (d.Month != previous.Month && ((d - previous).Days == 28 || (d - previous).Days == 35))
                return false;
            previous = d;
        }
    }
    return true;
}
于 2013-03-11T01:52:05.967 に答える
2

構造を見ることをお勧めしTimeSpanます。演算子のオーバーロードのおかげで、TimeSpan2 つの日付を減算して を取得しTimeSpan、2 つの日付の差を表す を取得できます。

http://msdn.microsoft.com/en-us/library/system.timespan.aspx

于 2013-03-11T01:33:37.883 に答える
1

さて、これががこの問題にどのように取り組むかについての私の最初の考えです。

まず、日付を表示順序に対応する序数値に変換する関数を定義します

int ToOrdinal(DateTime d, DateTime baseline) {
   if (d.Day <= 7
       && d.DayInWeek == baseline.DayInWeek) {
      // Since there is only one "First Friday" a month, and there are
      // 12 months in year we can easily compose the ordinal.
      // (As per default.kramer's comment, months normalized to [0,11].)
      return d.Year * 12 + (d.Month - 1);
   } else {
      // Was not correct "kind" of day -
      // Maybe baseline is Tuesday, but d represents Wednesday or
      // maybe d wasn't in the first week ..
      return 0;
   }
}

var dates = ..;
var baseline = dates.FirstOrDefault();
var ordinals = dates.Select(d => ToOrdinal(d, baseline));

次に、提供された日付について、次のような順序シーケンスになります。

[24156 + 0, 24156 + 1, 24156 + 2, 24156 + 3]

[24156 + 0, 24156 + 1, /* !!!! */ 24156 + 3]

ここから、リストを反復し、整数がギャップやストールなしで順番に発生することを確認するのは簡単なことです。つまり、各アイテム/整数は前のものよりも正確に1つ多くなります。

于 2013-03-11T03:40:36.903 に答える
0

あなたがしようとしていることを誤解している可能性がありますが、古い日付を処理する必要がないと仮定すると、これでうまくいくと思います。「合計月」に変換された日付にギャップがあるかどうかを確認します

int totalMonths = date.Year * 12 + (date.Month - 1);
于 2013-03-11T01:56:27.913 に答える