2017-01-20 3 views
1

(繰り返しパターンに基づいて)日付のシーケンスを返すクラスを持っています(または持っています)。シーケンスは、有限の終了(#結果または終了の日付)または無限であってもよい。特別な「結合」列挙子を作成する方法

私がしたいのは、そのような列挙子(開始日)のリストを取得し、それらのシーケンスを日付順の列挙可能な出力シーケンスに「結合」するクラスを作成することです。終了する(または開始しない)ソース列挙、および同じ日付を生成する複数のソース列挙を処理する必要があります。

私の質問はこれをどのようにして達成するのですか?

詳細情報(役立つ場合):
RecurrencePatternsの値が-
(1)「毎月1日、2017年7月4日」;

第一 - :
(2)「各四半期の終わり、6つの出現のみ」
(3)「年の最後の日」
と私は2017年1月1日に開始し、私は出力になりたいです2017年1月(1)、
2017年2月1日(1)、
2017年3月1日(1)、
2017年3月31日(2)、
2017年4月1日(1)、
2017年5月1日(1) 、
第1回2017年6月(1)、
第30 2017年6月(2)
2017年7月1日(1)、[(1) - 最後の列挙次はその終了日後であるため]
2017年9月30日(2)、
2017年12月31日(2、3)、[同じ日付を持つ2つのイベント]
2018年3月31日(2)、
2018年6月30日(2)〔(2) - 最後の列挙それだけで生成するので、6]
2018年12月31日(3)、
2019年12月31日(3)、
2020年12月31日(3)、 など

実際のアウトプットRecurrenceパターンクラスのtは、おそらくソースと日付を含む何らかの並べ替えのEventInfoクラスになります。 'combined'列挙子の出力は似ていますが、複数のRecurrence EventInfoの日付が同じであれば、単一のDateを持つ単一のEventInfoとその日付を返すソースのリストを出力します。

+2

あなたは、複数の終端していない列挙体の出力をマージしたいと思いますか?それをソートしますか? –

+0

あなたの最初の質問には「はい」、2番目の質問には「並べ替え」があります。ソートは各ソースから返された(単一の)日付のそれぞれで行われます。最も早いものが返されますその配列)。プロセスが繰り返されます。 –

+0

OK、各列挙体でGetEnumerator()を開始してリストに入れ、各列挙子でMoveNext()を呼び出すことができます。メインループでは、各列挙子のCurrentをチェックし、最も低い値を返したMoveNext()を繰り返します。 –

答えて

2

重複が返されるようにするには、MoreLINQでSortedMergeを使用するか、重複が望ましくない場合はOrderedMergeを使用する必要があります。ここで


あなたはNuGetパッケージをインストールしたくなかった、または上書きのどれもがニーズに適していない場合は、それを書くかもしれない方法です。

static IEnumerable<DateTime> CombineDateTimes(IEnumerable<IEnumerable<DateTime>> list) { 
    // keep track of which enumerators are still available 
    var eligible = list.Select(l => l.GetEnumerator()).Where(l => l.MoveNext()).ToList(); 

    while (eligible.Any()) { 
     // find the lowest enumerator 
     IEnumerator<DateTime> min = eligible.First(); 
     foreach (var l in eligible.Skip(1)) { 
      if (l.Current < min.Current) { 
       min = l; 
      } 
     } 

     // here is our lowest 
     yield return min.Current; 

     if (!min.MoveNext()) { 
      // if the enumerator ends, 
      // remove it from the list of eligible enumerators 
      eligible = eligible.Remove(min); 
     } 
    } 
} 
1

このような何かが、私は思う:ジェイコブとエドからの回答に

public static IEnumerable<DateTime> SortDates(IEnumerable<IEnumerable<DateTime>> iidt) 
{ 
    var enumerators = iidt.Select(iedt => iedt.GetEnumerator()) 
         .Where(e => e.MoveNext()) 
         .ToList(); 

    while (enumerators.Any()) 
    { 
     var lowest = enumerators.OrderBy(e => e.Current).First(); 

     yield return lowest.Current; 

     if (!lowest.MoveNext()) 
     { 
      enumerators.Remove(lowest); 
     } 
    } 
} 
+0

偉大な心など、等 –

+0

@JacobKrallええ、私はあなたのものが上がってくるのを見て、私が私の書き込みを終えるまで私の目を避けました。クリーンルーム、私は誓う! –

+1

私はあなたを信じています:)私は私の投稿後わずか数秒であなたの元のコメントを見ました。 –

0

おかげで、私は誰かが役に立つかもしれない次のコードを思い付くことができました:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

using NUnit.Framework; 

namespace TIPS.UnitTest 
{ 
public class EventInfo 
{ 
    public DateTime Date; 
    public EventSource EventSource; 
    public List<EventSource> AdditionalEventSources; // Left null if no additional sources 
} 

public abstract class EventSource 
{ 
    public string Name 
    { 
     get { return GetType().Name; } 
    } 

    public abstract IEnumerable<DateTime> RecurringDates(); 
} 

public interface IEventInfoGenerator 
{ 
    IEnumerable<EventInfo> GenerateEvents(List<EventSource> eventSources); 
} 

public class MyAnswerEventInfoGenerator: IEventInfoGenerator 
{ 
    public IEnumerable<EventInfo> GenerateEvents(List<EventSource> eventSources) 
    { 
     // Combine the Event Sources and their DateEnumerators ignoring any without Dates to return 
     var sourceEnumerators = eventSources 
      .Select(es => 
         new 
          { 
           Source = es, 
           DateEnumerator = es.RecurringDates().GetEnumerator() 
          }) 
      .Where(e => e.DateEnumerator.MoveNext()) 
      .ToList(); 

     // Keep going until there is nothing left 
     while (sourceEnumerators.Any()) 
     { 
      // Find the earliest date 
      var earliestSource = sourceEnumerators.OrderBy(se => se.DateEnumerator.Current).First(); 

      // Prepare the EventInfo 
      var eventInfo = new EventInfo 
           { 
            Date = earliestSource.DateEnumerator.Current, 
            EventSource = earliestSource.Source 
           }; 

      // Remove the EventSource if it has no more Dates 
      if (!earliestSource.DateEnumerator.MoveNext()) 
      { 
       sourceEnumerators.Remove(earliestSource); 
      } 

      // Quick check to see if there are other EventSources with the same date (no need to create a list if not necessary 
      if (sourceEnumerators.Any(se => se != earliestSource && se.DateEnumerator.Current == eventInfo.Date)) 
      { 
       // Yes, there are so create a list for them 
       eventInfo.AdditionalEventSources = new List<EventSource>(); 

       // Go through each 
       foreach (var additionalSourceEnumerator in sourceEnumerators.Where(se => se != earliestSource && se.DateEnumerator.Current == eventInfo.Date).ToArray()) 
       { 
        // Add it to the EventInfo list 
        eventInfo.AdditionalEventSources.Add(additionalSourceEnumerator.Source); 

        // And remove them if they are spent 
        if (!additionalSourceEnumerator.DateEnumerator.MoveNext()) 
        { 
         sourceEnumerators.Remove(additionalSourceEnumerator); 
        } 
       } 
      } 

      yield return eventInfo; 
     } 
    } 
} 


[TestFixture] 
public class RecurrenceTests 
{ 
    static IEnumerable<EventSource> CreateTestEventSources() 
    { 
     yield return new EventSource1(); 
     yield return new EventSource2(); 
     yield return new EventSource3(); 
     yield return new EmptyEventSource(); 
    } 

    static void TestStackoverAnswer(IEventInfoGenerator answer) 
    { 
     var testEventSources = CreateTestEventSources().ToList(); 

     foreach (var eventInfo in answer.GenerateEvents(testEventSources)) 
     { 
      Debug.Write($"{eventInfo.Date} - {eventInfo.EventSource.Name}"); 

      if (eventInfo.AdditionalEventSources != null) 
      { 
       Debug.Write(", " + string.Join(", ", eventInfo.AdditionalEventSources.Select(ev => ev.Name))); 
      } 

      Debug.WriteLine(string.Empty); 
     } 
    } 

    [Test] 
    public void TestMyGo() 
    { 
     TestStackoverAnswer(new MyAnswerEventInfoGenerator()); 
    } 
} 

public class EventSource1: EventSource 
{ 
    public override IEnumerable<DateTime> RecurringDates() 
    { 
     yield return new DateTime(2017, 1, 1); 
     yield return new DateTime(2017, 2, 1); 
     yield return new DateTime(2017, 3, 1); 
     yield return new DateTime(2017, 4, 1); 
     yield return new DateTime(2017, 5, 1); 
     yield return new DateTime(2017, 6, 1); 
     yield return new DateTime(2017, 7, 1); 
    } 
} 

public class EventSource2: EventSource 
{ 
    public override IEnumerable<DateTime> RecurringDates() 
    { 
     yield return new DateTime(2017, 3, 31); 
     yield return new DateTime(2017, 6, 30); 
     yield return new DateTime(2017, 9, 30); 
     yield return new DateTime(2017, 12, 31); 
    } 
} 

public class EventSource3: EventSource 
{ 
    public override IEnumerable<DateTime> RecurringDates() 
    { 
     yield return new DateTime(2017, 12, 31); 
     yield return new DateTime(2018, 12, 31); 
     yield return new DateTime(2019, 12, 31); 
    } 
} 

public class EmptyEventSource: EventSource 
{ 
    public override IEnumerable<DateTime> RecurringDates() 
    { 
     yield break; 
    } 
} 

}

テストの出力は次のようになります。 -

01/01/2017 00:00:00 - EventSource1 
01/02/2017 00:00:00 - EventSource1 
01/03/2017 00:00:00 - EventSource1 
31/03/2017 00:00:00 - EventSource2 
01/04/2017 00:00:00 - EventSource1 
01/05/2017 00:00:00 - EventSource1 
01/06/2017 00:00:00 - EventSource1 
30/06/2017 00:00:00 - EventSource2 
01/07/2017 00:00:00 - EventSource1 
30/09/2017 00:00:00 - EventSource2 
31/12/2017 00:00:00 - EventSource2, EventSource3 
31/12/2018 00:00:00 - EventSource3 
31/12/2019 00:00:00 - EventSource3 
関連する問題