使用复杂的位掩码确定日期设置的位

Rob*_*nik 7 c# algorithm bitmask

我有一个转换掩码代表一周中的几天:

Sunday = 1
Monday = 2
Tuesday = 4
...
Saturday = 64
Run Code Online (Sandbox Code Playgroud)

我正在使用位掩码,因为几天(至少一天)可能设置为1.

问题

然后我得到约会.任何日期.并且基于date.DayOfWeek我需要返回在位掩码中设置的第一个最近的日期.所以,我的方法可以返回当天或之间的任何一天datedate + 6.

例1

我的位掩码定义了设置为1的所有日期.在这种情况下,我的方法应返回相同的日期,因为在位date.DayOfWeek掩码中设置.

例2

我的位掩码定义只有星期三设置为1.如果我的传入日期是星期二,我应该返回date+1(这是星期三).但如果收到的日期是星期四,我应该返回date+6(这也是星期三).

解决这个问题的最快和最优雅的方法是什么?为什么也最快?因为我需要多次运行,所以如果我可以使用某种缓存结构来更快地获取日期,那么这将是首选.

您能否以优雅的方式提出一些指导来解决这个问题?我不想最终得到一个充满ifs和switch-case语句的长意大利面条代码......

重要提示:重要的是要注意,如果位掩码有助于提高性能和简化代码,则可以更改或替换其他位掩码.所以位掩码不是一成不变的......

一种可能的方法

每天生成一组偏移并将其保存在私有类变量中是明智的.生成一次并在之后重复使用,如:

return date.AddDays(cachedDayOffsets[date.DayOfWeek]);
Run Code Online (Sandbox Code Playgroud)

这样我们根本就不使用位掩码,唯一的问题是如何以最快的速度和尽可能短的代码生成数组.

Mik*_*sen 1

您可能讨厌这个答案,但也许您可以沿着新的方向前进。您说性能非常重要,所以也许最好在某些数据结构中预先索引所有答案。该数据结构可能有些复杂,但它可以封装在自己的小世界中,并且不会干扰您的主代码。我想到的数据结构是一个整数数组。如果您允许星期一、星期五和星期六,这些整数将是:

[1][0][3][2][1][0][0]
Run Code Online (Sandbox Code Playgroud)

好吧,很奇怪吧?这基本上就是本周的“休假天数”列表。周日,“距离一周中允许的下一天还有 1 天”。周一还有 0 天,周二还有 3 天。现在,一旦您构建了此列表,您就可以非常轻松且快速地计算出需要在日期中添加多少天才能获得下一次出现。希望这有帮助?

生成这些偏移量

这是生成这些偏移量的代码:

this.dayOffsets = new int[] {
    this.Sundays ? 0 : this.Mondays ? 1 : this.Tuesdays ? 2 : this.Wednesdays ? 3 : this.Thursdays ? 4 : this.Fridays ? 5 : 6,
    this.Mondays ? 0 : this.Tuesdays ? 1 : this.Wednesdays ? 2 : this.Thursdays ? 3 : this.Fridays ? 4 : this.Saturdays ? 5 : 6,
    this.Tuesdays ? 0 : this.Wednesdays ? 1 : this.Thursdays ? 2 : this.Fridays ? 3 : this.Saturdays ? 4 : this.Sundays ? 5 : 6,
    this.Wednesdays ? 0 : this.Thursdays ? 1 : this.Fridays ? 2 : this.Saturdays ? 3 : this.Sundays ? 4 : this.Mondays ? 5 : 6,
    this.Thursdays ? 0 : this.Fridays ? 1 : this.Saturdays ? 2 : this.Sundays ? 3 : this.Mondays ? 4 : this.Tuesdays ? 5 : 6,
    this.Fridays ? 0 : this.Saturdays ? 1 : this.Sundays ? 2 : this.Mondays ? 3 : this.Tuesdays ? 4 : this.Wednesdays ? 5 : 6,
    this.Saturdays ? 0 : this.Sundays ? 1 : this.Mondays ? 2 : this.Tuesdays ? 3 : this.Wednesdays ? 4 : this.Thursdays ? 5 : 6
};
Run Code Online (Sandbox Code Playgroud)

这会产生前向偏移。因此,对于任何给定日期,您只需通过以下方式即可获取其后的实际适用日期:

SomeDate.AddDays(this.dayOffsets[(int)SomeDate.DayOfWeek]);
Run Code Online (Sandbox Code Playgroud)

如果您需要获取最近的过去日期,您可以重复使用相同的数组并使用以下公式计算出来:

SomeDate.AddDays((this.dayOffsets[(int)SomeDate.DayOfWeek] - 7) % 7);
Run Code Online (Sandbox Code Playgroud)