顺序 - 后续年份的相同日期

时间:2017-02-12 12:56:23

标签: f# sequence

我想创建一个序列,该序列作为结果返回所有年份的星期几与函数参数相同 (例如:所有年份,即2月12日是星期日,自开始日期起)。

let myDate (dw:System.DayOfWeek) (start:System.DateTime) =
    seq {
            ...
        }
希望你理解我的意思。

3 个答案:

答案 0 :(得分:4)

这个怎么样:

let myDate (dw:System.DayOfWeek) (start:System.DateTime) =
    Seq.initInfinite ((+)1) // from 1..∞
    |> Seq.map start.AddYears
    |> Seq.takeWhile (fun x -> x < DateTime.MaxValue)
    |> Seq.filter (fun x -> x.DayOfWeek = dw)
    |> Seq.map (fun x -> x.Year)

myDate System.DayOfWeek.Monday (new DateTime(2001,1,1)) |> Dump

let myDate (dw:System.DayOfWeek) (start:System.DateTime) =
    let rec inner i =
        seq {
            let someDay = start.AddYears(i)
            if someDay.DayOfWeek = dw then yield someDay.Year
            yield! inner (i+1)
        }
    inner 1

myDate System.DayOfWeek.Monday (new DateTime(2001,12,1)) |> Dump

答案 1 :(得分:1)

斯图尔特的答案很好,但我不能帮助,但我想,#呃,我删除了一些代码。&#34;你知道,从特定月/日开始的未经确定的年份序列开始,让调用者确定要采取的数量或添加他们自己的过滤器。

你应该思考&#34;愚弄差事&#34;在此刻。 :)我遇到的第一个问题 - 因为我的第二次虚弱测试失败了 - 是你不能永远地继续递增DateTime,所以你必须写代码来限制它。

因此,由于处理了真实数据的变幻莫测,我得到了更多的代码而不是更少的代码:

// All instances of this specified month/day beginning with 'start'.
let myDate (dw:System.DayOfWeek) (start:System.DateTime) =
    // Start with a sequence of one date for each year...
    seq {
        // Don't run the date past DateTime.MaxValue, there lurks an
        // ArgumentOutOfRangeException. Comparison also must be on the
        // valid side of DateTime.MaxValue. Don't bother with try/with
        // here in a sequence expression, you can't do that.
        let maxDateBarrier = DateTime.MaxValue.AddYears(-1)
        let mutable keepGoing, date = true, start

        while keepGoing do
            yield date

            // if date.Year % 100 = 0 then printfn "%A" date.Year

            if date <= maxDateBarrier then
                date <- date.AddYears(1)
            else
                keepGoing <- false
    }
    |> Seq.where (fun date -> date.DayOfWeek = dw)

有点罗嗦。测试#1工作正常:

let printDates (dates : DateTime seq) =
    for date in dates do
        printfn "%A" date.Year

// Take the next 5
myDate DayOfWeek.Sunday DateTime.Now
    |> Seq.take 5
    |> printDates

测试#2实际上遍历了序列中日期的所有

// Take up to 5 before 2040.
// Note: this statement actually iterates through *all* the years in the
// sequence if you truncate to a length longer than Seq.where returns.
myDate DayOfWeek.Sunday (DateTime(2017, 2, 13))
    |> Seq.where (fun date -> date.Year < 2040)
    |> Seq.truncate 5
    |> printDates

测试#2是将endDate添加到myDate功能的原因吗?不,它更适合使用序列。使用takeWhile代替where

// Try again: Take up to 5 before 2040.
// Terminate the sequence early with takeWhile.
myDate DayOfWeek.Sunday (DateTime(2017, 2, 13))
    |> Seq.takeWhile (fun date -> date.Year < 2040)
    |> Seq.truncate 5
    |> printDates

好多了。错过了我的目标&#34;更少的代码,&#34;但我没关系。的:)

答案 2 :(得分:1)

我太懒了,不能对此进行编码,但我会采用这种方式来找到一种考虑闰年的有效且快速的算法。我认为这是一项有趣的任务,将速度与其他答案进行比较会很有趣。

有14种可能的日历。这些日历如何重复是你可以快速找到的东西,如果你google它。我发现了这个。

“公历”在28年的周期中重复出现。特定非闰年的日历在11年后重复两次,并在28年的跨度中重复六年。闰年的日历重演每28年一次。“

一年中某一天如何重复,我猜可能会稍微复杂一点,但如果是这样的话,那就不多了。

当然,除了2月29日之外,七个非飞跃日历中的任何一个当然都会与1月到2月的一个闰年日历相匹配。初看起来似乎很明显,从3月开始也会有一场比赛,除了与Jan ... Feb28相比,它会偏向一天和一个日历。需要检查。我想知道这是否会影响算法,如果是,那将如何。

如果您的意见是2月29日,那么显然只需要考虑闰年。

从中可以很容易地编写算法。

希望这在某种程度上有意义。我不确定每400年会发生什么,或者其他什么可能出错。但是很容易通过所有合理的日期来测试,并在需要时进行调整。