我想创建一个序列,该序列作为结果返回所有年份的星期几与函数参数相同 (例如:所有年份,即2月12日是星期日,自开始日期起)。
let myDate (dw:System.DayOfWeek) (start:System.DateTime) =
seq {
...
}
希望你理解我的意思。
答案 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;在此刻。 :)我遇到的第一个问题 - 因为我的第二次虚弱测试失败了 - 是你不能永远地继续递增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年会发生什么,或者其他什么可能出错。但是很容易通过所有合理的日期来测试,并在需要时进行调整。