让我们把问题分成几个小部分。
注意:以下所有方法都应该放在这样的类中
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);