F# 顺序-以后年份中的同一日期
我想创建一个序列,当一周中的某一天与函数参数中的日期相同时,该序列将返回所有年份的结果 (例如:自开始日期起,2月12日为星期日的所有年份) 希望你明白我的意思。这个怎么样:F# 顺序-以后年份中的同一日期,f#,sequence,F#,Sequence,我想创建一个序列,当一周中的某一天与函数参数中的日期相同时,该序列将返回所有年份的结果 (例如:自开始日期起,2月12日为星期日的所有年份) 希望你明白我的意思。这个怎么样: let myDate (dw:System.DayOfWeek) (start:System.DateTime) = Seq.initInfinite ((+)1) // from 1..∞ |> Seq.map start.AddYears |> Seq.takeWhile (fun
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
Stuart的回答很好,但我忍不住想“呃,我应该删除一些代码。”你知道,从一个不确定的年份序列开始,以特定的月份/天为单位,让打电话的人决定有多少个需要使用或添加他们自己的过滤器 在这一点上,你应该考虑“傻瓜的差事”:)我遇到的第一个问题——因为我的第二个微弱测试失败了——是你不能永远快乐地继续递增
日期时间,所以你必须编写代码来限制它
因此,由于处理真实数据的变幻莫测,我最终得到了更多而不是更少的代码:
// 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)
测试#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
好多了。我没有达到“减少代码”的目标,但我同意:)我懒得编写代码,但我会这样做,以找到一种考虑闰年的有效快速算法。我认为这是一项有趣的任务,将速度与其他答案进行比较会很有趣
有14种可能的日历。如果你在谷歌上搜索这些日历,你会很快发现它们是如何重复的。我找到了这个
“公历以28年为一个周期重复。特定非闰年的日历在11年后重复两次,在6年后重复一次。闰年的日历每28年重复一次。”
我想,一年中某一天是如何重复的,可能会稍微复杂一些,但如果是这样的话,就不会太复杂了
当然,七个非闰年日历中的任何一个都将与1月至2月的一个闰年日历相匹配,当然2月29日除外。乍一看似乎很明显,从3月起也会有一场比赛,只是与1月、2月28日相比会有一天和一个日历的偏差。需要检查。我想知道这是否会影响算法,如果会,如何影响
如果您的输入是2月29日,那么显然只需要考虑闰年
因此,编写一个算法应该非常简单
希望这有点道理。我不确定每400年会发生什么,或者是否会出现其他问题。但是,很容易通过所有合理的日期进行测试,并在需要时进行调整。我们确实理解您的意思,但您尝试过什么,您发现有什么棘手之处?这不是一个代码编写服务…(id>(+)1)
是一种有趣的说法(+)1)
;-]哦,是的,我把这归咎于缺少咖啡:-请注意,闰年是一个你将不得不处理的极端情况。在2012年2月29日(星期三)调用AddYears(6)
将产生2018年2月28日(也将是星期三)。因此,除非您还通过AddYears(i)
调用检查日历日期是否未更改,否则使用这种方法会出现误报。有关如何处理2月29日的详细信息,请参阅。您是对的,我将稍后再讨论这个问题并解决闰年问题。这是更多的代码(不是减少代码应该是目标),并增加了可变性。但是看到其他答案总是很好的=)我认为“更少的代码”应该是目标,因为这通常有助于可读性。(当然,如果较短的代码是Perl一行程序一样的乱七八糟的话,这就不适用了。)Antoine de Saint Exupéry曾经说过,“完美是实现的,不是当没有什么可添加的时候,而是当没有什么可带走的时候。”他完全正确。通常,当您将设计(或代码)精简到基本要素时,结果会更优雅、更易于阅读。因此,我通常努力将“更少的代码”作为经验法则的设计目标。@Stuart是的,我想我已经清楚地表明我“没有达到‘更少的代码’的目标”。:)我感兴趣的是出现的边界情况、终止的未终止序列以及序列操作的误用。请注意,我对闰年还不够认真,那是午餐时间的沉思
// 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)
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
// 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
// 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