将星期几的列表分组为连续几天的组

时间:2016-07-18 09:12:23

标签: c# collections grouping dayofweek nodatime

我正在使用C#创建一个包含NodaTime.IsoDayOfWeek天列表的函数。我想将输入分组为连续几天。

例如,以下列表应提供以下输出:

{ Mon, Tue } => { { Mon, Tue } }
{ Mon, Wed } => { { Mon }, { Wed } }
{ Mon, Tue, Fri, Sat } => { { Mon, Tue }, { Fri, Sat } }
{ Mon, Wed, Fri, Sun } => { { Sun, Mon }, { Wed }, { Fri } }
{ Mon, Tue, Wed, Thu, Fri, Sat, Sun } => { { Mon, Tue, Wed, Thu, Fri, Sat, Sun } }

请注意,星期日和星期一是连续的,因此列表是一个闭环。此外,应该对结果列表进行排序,使得第一天直接在输入列表中未包含的日期之后(如果包含完整列表,则为星期一)。

Mauricio Scheffer published a great extension method to group consecutive integers here:

public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> list) {
    var group = new List<int>();
    foreach (var i in list) {
        if (group.Count == 0 || i - group[group.Count - 1] <= 1)
            group.Add(i);
        else {
            yield return group;
            group = new List<int> {i};
        }
    }
    yield return group;
}

但是我无法弄清楚如何将此修改为分组天数,因为星期日和星期一也是连续的。如何将周日和周一连续几天分组?

3 个答案:

答案 0 :(得分:1)

样本输入是有序数组。想象一下,您的输入是1到7之间的数组而不是顺序,您必须使用2个循环来按条件<?php //blog posts shortcode function my_recent_post() { global $post; $html = ""; $my_query = new WP_Query( array( 'post_type' => 'post', 'cat' => '4', 'posts_per_page' => 1 )); if( $my_query->have_posts() ) : while( $my_query->have_posts() ) : $my_query->the_post(); $html .= "<span>" . the_post_thumbnail( 'medium', array( 'class' => 'img-responsive') ) . "</span>"; $html .= "<h2>" . the_title() . "</h2>"; $html .= "<p>" . the_excerpt() . "</p>"; endwhile; endif; return $html; } add_shortcode( 'blog', 'my_recent_post' ); ?> 查找每个下一个数字。 这是我对你的解决方案的想法:

Abs(current-next) == 1 || Abs(current-next) == 6

答案 1 :(得分:1)

我没有更有效地使用LINQ,但我认为这样做。这只是一个简单的控制台App。

 public enum Days
        {
            Mon = 1,
            Tue,
            Wed,
            Thur,
            Fri,
            Sat,
            Sun
        }






public static IEnumerable<IEnumerable<int>> GroupDay(IEnumerable<int> ListOfDays)        
{
            List<List<int>> Response = new List<List<int>>();
            List<int> Queue = new List<int>();
            var ListToIterate = ListOfDays.Distinct().OrderBy(d => d).ToList();
            foreach (var item in ListToIterate)
            {

                if (Queue.Count == 0)
                {
                    Queue.Add(item);
                }
                else
                {
                    if ((item - 1) == Queue[Queue.Count - 1])
                    {
                        Queue.Add(item);
                    }
                    else if (item != (int)Days.Sun)
                    {
                        Response.Add(Queue);
                        Queue = new List<int>() { item };
                    }
                }

                if (item == ListToIterate.LastOrDefault())
                    Response.Add(Queue);

                //Handle Sunday
                if (item == (int)Days.Sun)
                {
                    //Check if Saturday exists, if exists then do not put sunday before Monday.
                    var FindSaturday = Response.Where(r => r.Contains((int)Days.Sat)).FirstOrDefault();
                    if (FindSaturday == null)
                    {
                        var FindMonday = Response.Where(r => r.Contains((int)Days.Mon)).FirstOrDefault();
                        if (FindMonday != null)
                        {
                            FindMonday.Insert(0, item);
                        }
                    }

                }

            }
            return Response;
        }

以下是我尝试使用某些用例的方法。

//List<int> ListOfDays = new List<int>() { DaysToNumber(Days.Mon), DaysToNumber(Days.Tue) };
            //List<int> ListOfDays = new List<int>() { DaysToNumber(Days.Mon), DaysToNumber(Days.Wed) };
            //List<int> ListOfDays = new List<int>() { DaysToNumber(Days.Mon), DaysToNumber(Days.Tue), DaysToNumber(Days.Fri), DaysToNumber(Days.Sat) };
            //List<int> ListOfDays = new List<int>() { DaysToNumber(Days.Mon), DaysToNumber(Days.Wed), DaysToNumber(Days.Fri), DaysToNumber(Days.Sun) };
            //List<int> ListOfDays = new List<int>() { DaysToNumber(Days.Mon), DaysToNumber(Days.Tue), DaysToNumber(Days.Wed), DaysToNumber(Days.Thur), DaysToNumber(Days.Fri), DaysToNumber(Days.Sat), DaysToNumber(Days.Sun) };
            List<int> ListOfDays = new List<int>() { DaysToNumber(Days.Mon),DaysToNumber(Days.Fri),  DaysToNumber(Days.Sun) };
            var ListToIterate = ListOfDays.Distinct().OrderBy(d => d).ToList();
            var result = GroupDay(ListToIterate);

答案 2 :(得分:0)

这是我最终选择的解决方案。我在这里使用过Linq,但它可以很容易地重写。我还为此编写了大量的单元测试,如果您想访问它们,请发表评论。

using NodaTime;
using System.Collections.Generic;
using System.Linq;

namespace Domain.Extensions
{
    public static class IsoDayOfWeekExtensions
    {
        public static IReadOnlyList<IReadOnlyList<IsoDayOfWeek>> GroupConsecutive(this IList<IsoDayOfWeek> days)
        {
            var groups = new List<List<IsoDayOfWeek>>();
            var group = new List<IsoDayOfWeek>();

            var daysList = days.Distinct().OrderBy(x => (int)x);
            foreach (var day in daysList)
            {
                if (!group.Any() || (int)day - (int)group.Last() == 1)
                {
                    group.Add(day);
                }
                else
                {
                    groups.Add(group);
                    group = new List<IsoDayOfWeek>() { day };
                }
            }

            // Last group will not have been added yet. Check if the last group can be combined with the first group (Sunday and Monday are also consecutive!)
            if (group.Contains(IsoDayOfWeek.Sunday) && groups.Any() && groups.First().Contains(IsoDayOfWeek.Monday))
            {
                // Insert before the Monday so that the days are in the correct consecutive order.
                groups.First().InsertRange(0, group);
            }
            else
            {
                groups.Add(group);
            }

            return groups.Select(x => x.ToList()).ToList();
        }
    }
}