这可能是一个新手问题,但这里有。
我有一种方法,其中一个类型的DayOfWeek列表附加了一周中的各个日子(可能是星期三和星期六,星期日,星期一和星期五等)。
鉴于该列表,我需要将其与Datetime参数进行比较,在DayOfWeek列表中找到DateTime参数最接近的Week Day,并根据列表中的Week Day参数将日期添加到DateTime参数。
例如,如果传入的DateTime参数是星期日,而我的DayOfWeek列表包含星期三和星期六,则该参数需要移回星期六,因为它在列表中最接近。
同样,如果我的列表包含星期日,星期一和星期六,并且传入的参数是星期四,则该参数必须移至星期六。
最后,如果参数与列表中的两个工作日相等(周三传入,周一和周五在列表中......或周日传入,周二和周五在列表中),则参数需要向前移动到下一个最接近的工作日(在第一种情况下,将是星期五,在第二种情况下是星期二)。
将下一个最接近的工作日的距离从传入的日期转换为int是理想的(至少对我而言),这样我可以做类似的事情:
passedInDate = passedInDate.AddDays(dayOfWeekDistance);
return passedInDate;
但我愿意接受建议。
我尝试过LINQ语句,例如:
int dayOfWeekDistance = targetDayOfWeekList.Min(x => (x - passedInDate));
但无济于事。必须有一些我想要的LINQ语句。
只是抬头,我无法上班的主要项目是,如果传递的日期是星期日,并且列表中最接近的星期日是星期六,那么从星期日回到星期六的日期是回溯的(类似的,如果传入的日期是星期一,而最接近的工作日是星期五,则日期需要一直遍历到星期五。)
如果我遗漏了任何内容,请告诉我,或者我只是没有意义。
欢迎所有帮助!感谢。
答案 0 :(得分:3)
让我们将问题分成几个小部分。
注意:以下所有方法都应该放在像这样的类
中public static class DayOfWeekExtensions
{
}
首先,您希望Sunday
成为一周中的最后一天,而DayOfWeek
enum
首先定义它。因此,让一个函数说明:
public static int GetIndex(this DayOfWeek source)
{
return source == DayOfWeek.Sunday ? 6 : (int)source - 1;
}
然后我们需要一个函数来计算两个DayOfWeek
值之间的距离(偏移量):
public static int OffsetTo(this DayOfWeek source, DayOfWeek target)
{
return source.GetIndex() - target.GetIndex();
}
还要添加一个给定一个数据透视的函数,并且两个DayOfWeek
值选择两者中最接近的值(应用您的前向优先级规则):
public static DayOfWeek Closest(this DayOfWeek pivot, DayOfWeek first, DayOfWeek second)
{
int comp = Math.Abs(first.OffsetTo(pivot)).CompareTo(Math.Abs(second.OffsetTo(pivot)));
return comp < 0 || (comp == 0 && first.GetIndex() > pivot.GetIndex()) ? first : second;
}
现在我们已经准备好实现从序列中找到最接近的一天的方法。它可以通过多种方式实现,这里是使用(最终!:) LINQ Aggregate
方法的实现:
public static DayOfWeek? Closest(this IEnumerable<DayOfWeek> source, DayOfWeek target)
{
if (!source.Any()) return null;
return source.Aggregate((first, second) => target.Closest(first, second));
}
最后,让我们添加一个计算最近距离的函数:
public static int ClosestDistance(this IEnumerable<DayOfWeek> source, DayOfWeek target)
{
return source.Closest(target)?.OffsetTo(target) ?? 0;
}
我们完成了。我们刚刚创建了一个简单的小型可重用实用程序类。
您案例中的用法是:
int dayOfWeekDistance = targetDayOfWeekList.ClosestDistance(passedInDate.DayOfWeek);
更新:事实证明您的要求不同。
应用相同的原理,首先我们需要一个函数来计算一周中两天之间的前后距离的最小值,并应用前向优先规则。
public static int MinDistanceTo(this DayOfWeek from, DayOfWeek to)
{
int dist = to - from;
return dist >= 4 ? dist - 7 : dist <= -4 ? dist + 7 : dist;
}
它的作用基本上是将可能的-6..6
包含范围内的值转换为-3..3
包含范围内的值。
然后我们还需要一个函数,它将使用Select
+ Aggregate
来实现相关方法(它也可以使用Min
和自定义比较器实现)。它基本上比较了两个绝对距离,并再次应用前向优先级规则:
public static int MinDistanceTo(this DayOfWeek from, IEnumerable<DayOfWeek> to)
{
if (!to.Any()) return 0;
return to.Select(x => from.MinDistanceTo(x)).Aggregate((dist1, dist2) =>
{
if (dist1 == dist2) return dist1;
int comp = Math.Abs(dist1).CompareTo(Math.Abs(dist2));
return comp < 0 || (comp == 0 && dist1 > 0) ? dist1 : dist2;
});
}
用法将是:
int dayOfWeekDistance = passedInDate.DayOfWeek.MinDistanceTo(targetDayOfWeekList);
答案 1 :(得分:1)
使用辅助函数,可以使用LINQ。
辅助函数使用效用函数计算最接近的星期几,以计算两个DOW之间的前进天数:
public int MinDOWDistance(DayOfWeek dow1, DayOfWeek dow2) {
int FwdDaysDiff(int idow1, int idow2) => idow2 - idow1 + ((idow1 > idow2) ? 7 : 0);
int fwd12 = FwdDaysDiff((int)dow1, (int)dow2);
int fwd21 = FwdDaysDiff((int)dow2, (int)dow1);
return fwd12 < fwd21 ? fwd12 : -fwd21;
}
然后你可以在列表中找到最近的DOW,并使用Aggregate
和LINQ返回正确的移动天数(和方向):
public int DaysToClosestDOW(DayOfWeek dow1, List<DayOfWeek> dowList) {
return dowList.Select(dow => {
var cdow = MinDOWDistance(dow1, dow);
return new { dow, dist = cdow, absdist = Math.Abs(cdow) };
})
.Aggregate((g1, g2) => (g1.absdist < g2.absdist) ? g1 : ((g1.absdist == g2.absdist) ? ((g1.dist > 0) ? g1 : g2) : g2)).dist;
}
我发现我可以使用元组从帮助函数返回absdist
,因为它已经知道它。然后我可以使用LINQ中的Tuple
:
public (int dist, int absdist) MinDOWDistance(DayOfWeek dow1, DayOfWeek dow2) {
int FwdDaysDiff(int idow1, int idow2) => idow2 - idow1 + ((idow1 > idow2) ? 7 : 0);
int fwd12 = FwdDaysDiff((int)dow1, (int)dow2);
int fwd21 = FwdDaysDiff((int)dow2, (int)dow1);
if (fwd12 < fwd21)
return (fwd12, fwd12);
else
return (-fwd21, fwd21);
}
public int DaysToClosestDOW(DayOfWeek dow1, List<DayOfWeek> dowList) {
return dowList.Select(dow => MinDOWDistance(dow1, dow))
.Aggregate((g1, g2) => (g1.absdist < g2.absdist) ? g1 : ((g1.absdist == g2.absdist) ? ((g1.dist > 0) ? g1 : g2) : g2)).dist;
}