在DayOfWeek列表中查找最接近的星期日[英] Find Closest Week Day in DayOfWeek List

本文是小编为大家收集整理的关于在DayOfWeek列表中查找最接近的星期日的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

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

我有一种方法,其中的Dayofweek列表附有一周中的各个日子(可能是星期三和周六,周日,星期一,星期一和星期五等).

鉴于该列表,我需要将其与DateTime参数进行比较,找到DateTime参数最接近DayofWeek列表中的工作日,并根据列表中的哪个工作日将天数添加到DateTime参数.

例如,如果要通过的日期参数是一个星期日,而我的Dayofweek列表包含一个星期三和星期六,则该参数需要回到周六,因为它是列表中最接近的.

同样,如果我的列表包含周日,星期一和星期六,并且通过的参数是星期四,则该参数必须移至星期六.

最后,如果该参数与列表的两周相距(周三通过了,星期一和星期五都在列表中...或周日通过,周二和星期五都在列表中),则参数需要前进到下一个最近的一周(在第一种情况下是星期五,在第二种情况下是星期二).

是理想的(至少对我而言),将下一个最接近的工作日的距离从过去的日期转换为int,这样我就可以做这样的事情:

passedInDate = passedInDate.AddDays(dayOfWeekDistance);
return passedInDate;

,但我对建议.

我尝试了linq语句,例如:

int dayOfWeekDistance = targetDayOfWeekList.Min(x => (x - passedInDate));

但无济于事.我必须有一些我缺少的花哨的linq语句.

只是一个头,我无法上班的主要项目是从周日回到周六回来的日期,如果日期是星期日,而最接近的星期是星期六(同样,如果,如果通过日期是星期一,最近的一周是星期五,该日期需要一直延伸至星期五).

.

请让我知道我是否错过了任何东西,或者我只是没有意义.

欢迎所有帮助!谢谢.

推荐答案

具有辅助功能,可以使用LINQ.

使用实用程序功能计算两个dows之间的前进天数:

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

然后,您可以在列表中找到最近的陶氏

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

其他推荐答案

让问题将问题分为几个小部分.

注意:以下所有方法都应该放入这样的类中

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包含范围转换为-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);

本文地址:https://www.itbaoku.cn/post/1556849.html

问题描述

This is probably a newbie question, but here goes.

I have a method where a type DayOfWeek List that gets appended with various days of the week (Could be Wednesday & Saturday, Sunday, Monday, & Friday, etc).

Given that list, I need to compare it to a Datetime parameter, find the Week Day the DateTime parameter is closest to in the DayOfWeek list, and add days to the DateTime parameter based on what Week Day it is in the list.

For example, if the DateTime parameter being passed in is a Sunday, and my DayOfWeek list contains a Wednesday and Saturday, the parameter needs to be moved back to Saturday since it is closest in the list.

Similarly, if my list contains Sunday, Monday, and Saturday, and the parameter passed in is Thursday, then the parameter would have to be moved to Saturday.

Finally, if the parameter is equidistant from two week days in the list (Wednesday is passed in and Monday and Friday are in the list... or Sunday is passed in and Tuesday and Friday are in the list), then the parameter needs to be moved forward to the next closest week day (which, in the first case, would be Friday, and Tuesday in the second case).

It would be ideal (at least for me), to convert the distance of the next closest week day from the passed in date to an int, that way I can do something like:

passedInDate = passedInDate.AddDays(dayOfWeekDistance);
return passedInDate;

But I am open to suggestions.

I have tried LINQ statements such as:

int dayOfWeekDistance = targetDayOfWeekList.Min(x => (x - passedInDate));

But to no avail. There has to be some fancy LINQ statements that I'm missing.

Just a heads up, the main item I can't get to work is for the date to backtrack from Sunday back to Saturday if the passed in date is Sunday and the closest week day in the list is Saturday (similarly, if the passed in date is Monday and the closest week day is Friday, the date would need to traverse all the way back to Friday).

Please let me know if I missed anything or I'm just plain not making sense.

All help is welcome! Thanks.

推荐答案

With a helper function, LINQ can be used.

The helper function computes the closest day of week using a utility function to compute the number of forward days between the two DOWs:

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

Then you can find the nearest DOW in the list and return the right number of days to move (and direction) using Aggregate with 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;
}

It occurred to me I could use a tuple to return the absdist from the helper function since it already knows it. Then I can just use the Tuple in the LINQ:

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

其他推荐答案

Let split the problem to several small parts.

NOTE: All the following methods are supposed to be put inside a class like this

public static class DayOfWeekExtensions
{
}

First, you want Sunday to be the last day of the week, while in the DayOfWeek enum it's defined first. So let make a function accounting for that:

public static int GetIndex(this DayOfWeek source)
{
    return source == DayOfWeek.Sunday ? 6 : (int)source - 1;
}

Then we need a function which calculates the distance (offset) between two DayOfWeek values:

public static int OffsetTo(this DayOfWeek source, DayOfWeek target)
{
    return source.GetIndex() - target.GetIndex();
}

Let also add a function which given a pivot and two DayOfWeek values selects the closest value of the two (applying your forward priority rule):

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

Now we are ready to implement the method which finds the closest day from a sequence. It can be implemented in many ways, here is the implementation using (finally! :) LINQ Aggregate method:

public static DayOfWeek? Closest(this IEnumerable<DayOfWeek> source, DayOfWeek target)
{
    if (!source.Any()) return null;
    return source.Aggregate((first, second) => target.Closest(first, second));
}

Finally, let add a function which calculates the closest distance:

public static int ClosestDistance(this IEnumerable<DayOfWeek> source, DayOfWeek target)
{
    return source.Closest(target)?.OffsetTo(target) ?? 0;
}

And we are done. We just created a small simple reusable utility class.

The usage in your case would be:

int dayOfWeekDistance = targetDayOfWeekList.ClosestDistance(passedInDate.DayOfWeek);

UPDATE: It turns out that your requirement is different.

Applying the same principle, first we need a function which calculates the minimum of the forward and backward distance between two days of the week, applying the forward precedence rule.

public static int MinDistanceTo(this DayOfWeek from, DayOfWeek to)
{
    int dist = to - from;
    return dist >= 4 ? dist - 7 : dist <= -4 ? dist + 7 : dist;
}

What it does basically is to convert the value from the possible -6..6 inclusive range to the value in the -3..3 inclusive range.

Then we'll need just one more function, which will implement the method in question by using Select + Aggregate (it can also be implemented with Min and custom comparer). It basically compares two absolute distances and again applies the forward priority rule:

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

And the usage will be:

int dayOfWeekDistance = passedInDate.DayOfWeek.MinDistanceTo(targetDayOfWeekList);