2016-07-18 41 views
2

Ich benutze C#, um eine Funktion zu erstellen, die eine Liste der NodaTime.IsoDayOfWeek Tage aufnimmt. Ich möchte die Eingabe in Gruppen von aufeinanderfolgenden Tagen gruppieren.Gruppieren einer Liste von Wochentagen in Gruppen von aufeinanderfolgenden Tagen

Zum Beispiel sollten die folgenden Listen geben die folgende Ausgabe:

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

Beachten Sie, dass Sonntag und Montag aufeinander folgend ist, so dass die Liste eine geschlossene Schleife ist. Zusätzlich sollten die resultierenden Listen so angeordnet werden, dass der erste Tag direkt auf einen Tag folgt, der nicht in der Eingabeliste enthalten ist (oder Montag, wenn die vollständige Liste enthalten ist).

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

Allerdings kann ich nicht herausfinden, wie diese seit Sonntag und Montag zu einer Gruppe Tagen ändern auch aufeinander folgend sind. Wie kann ich aufeinanderfolgende Tage gruppieren, wobei Sonntag und Montag auch als aufeinanderfolgend gelten?

+1

[Check this] (http://stackoverflow.com/questions/4681949/use-linq-to-group-a-sequence-of-numbers-with-no-gaps) - Loved dtb Antwort - Sehen Sie, wie Sie es an Ihre Bedürfnisse anpassen können –

Antwort

0

Dies ist die Lösung, mit der ich endete. Ich habe Linq hier verwendet, aber es könnte leicht ohne geschrieben werden. Ich habe auch eine umfangreiche Reihe von Komponententests dafür geschrieben, bitte kommentieren Sie, wenn Sie Zugang zu ihnen haben möchten.

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

Der Beispieleingang ist ein sequenzielles Array. Stellen Sie sich vor, Ihre Eingabe ist ein Array von 1 bis 7 und nicht in der Reihenfolge, Sie müssen 2 Schleifen verwenden, um jede nächste Zahl nach der Bedingung Abs(current-next) == 1 || Abs(current-next) == 6 zu finden. Das ist meine Idee für Ihre Lösung:

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

Ich habe nicht LINQ effektiver, aber ich denke, dies zu tun. Dies ist nur eine einfache Konsole 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; 
     } 

und hier ist, wie ich einige Anwendungsfälle ausprobiert.

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