2016-07-18 6 views
2

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

私は日曜日と月曜日はまた、連続しているので、グループの日にこれを修正する方法を見つけ出すことはできませんが。日曜日と月曜日が連続していると考えられる連続日をグループ化するにはどうすればよいですか?

+1

(http://stackoverflow.com/questions/4681949/use-linq-to-group-a-sequence-of-numbers-with-no-gaps)[これをチェック] - 好きDTBの答えを - あなたのニーズにどのように適応できるかを見てください –

答えて

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

サンプル入力はシーケンス配列です。あなたの入力が1から7の配列であり、順番ではないとしたら、2つのループを使ってそれぞれの次の番号を条件Abs(current-next) == 1 || Abs(current-next) == 6で見つける必要があります。 これはあなたのソリューションのための私の考えです:

public static IEnumerable<IEnumerable<int>> GroupDay(IEnumerable<int> list) 
    { 
     List<int> input = new List<int>(list); 

     while (input.Count > 0) 
     { 
      int i = input[0]; 
      var group = new List<int>(); 
      group.Add(i); 
      input.RemoveAt(0); 

      for (int j = 0; j < input.Count;) 
      { 
       if (Math.Abs(group[group.Count - 1] - input[j]) == 1 
        || Math.Abs(group[0] - input[j]) == 6) 
       { 
        group.Add(input[j]); 
        input.RemoveAt(j); 
       } 
       else 
       { 
        j++; 
       } 
      } 

      // Sort output 
      group.Sort((x, y) => { 
       if (Math.Abs(x - y) == 6) 
       { 
        // Sunday and Monday case 
        return y - x; 
       } 
       else 
        return x - y; 
      }); 
      yield return group; 
     } 
    } 
1

私はより効果的にLINQを使用していませんでしたが、私はこれがそうなると思います。これは単なるコンソールアプリです。

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); 
関連する問題