首页 文章

在DayOfWeek列表中找到最接近的工作日

提问于
浏览
2

这可能是一个新手问题,但这里有 .

我有一个方法,其中一个类型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语句 .

只是抬头,我无法上班的主要项目是,如果传递的日期是星期日,并且列表中最接近的星期几是星期六,那么从星期日回到星期六的日期将回溯到星期六(类似地,如果传入日期是星期一,最接近的星期日是星期五,日期需要一直遍历到星期五) .

如果我错过任何事情或者我只是没有意义,请告诉我 .

欢迎大家帮忙!谢谢 .

2 回答

  • 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,并使用带有LINQ的 Aggregate 返回正确的移动天数(和方向):

    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;
    }
    
  • 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();
    }
    

    还要添加一个给定一个pivot的函数,并且两个 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);
    

    UPDATE: 事实证明你的要求是不同的 .

    应用相同的原理,首先我们需要一个函数来计算一周中两天之间的前后距离的最小值,并应用前向优先规则 .

    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);
    

相关问题