純粋な LINQ を使用してこれに完全にアプローチすることは、実際には非常に困難です。作業を楽にするために、列挙型を変換できるヘルパー メソッドを少なくとも 1 つ記述する必要があります。以下の例を見てください。ここではIEnumerable
ofを使用し、 2 つの要素を 1 つに結合TimeInterval
するカスタムメソッド (C# イテレータで実装) を用意しています。Split
Tuple
class TimeInterval
{
DateTime Start;
DateTime End;
int Value;
}
IEnumerable<TimeInterval> ToHourlyIntervals(
IEnunumerable<TimeInterval> halfHourlyIntervals)
{
return
from pair in Split(halfHourlyIntervals)
select new TimeInterval
{
Start = pair.Item1.Start,
End = pair.Item2.End,
Value = pair.Item1.Value + pair.Item2.Value
};
}
static IEnumerable<Tuple<T, T>> Split<T>(
IEnumerable<T> source)
{
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
T first = enumerator.Current;
if (enumerator.MoveNext())
{
T second = enumerator.Current;
yield return Tuple.Create(first, second);
}
}
}
}
問題の最初の部分にも同じことが当てはまります (TimeInterval
文字列のリストから 30 分ごとの s を抽出します)。
IEnumerable<TimeInterval> ToHalfHourlyIntervals(
IEnumerable<string> inputLines)
{
return
from triple in TripleSplit(inputLines)
select new TimeInterval
{
Start = DateTime.Parse(triple.Item1.Replace("Start: ", "")),
End = DateTime.Parse(triple.Item2.Replace("End: ", "")),
Value = Int32.Parse(triple.Item3)
};
}
TripleSplit
ここでは、aを返すカスタム メソッドを使用しますTuple<T, T, T>
(これは簡単に記述できます)。これを実装すると、完全なソリューションは次のようになります。
// Read data lazilzy from disk (or any other source)
var lines = File.ReadLines(path);
var halfHourlyIntervals = ToHalfHourlyIntervals(lines);
var hourlyIntervals = ToHourlyIntervals(halfHourlyIntervals);
foreach (var interval in hourlyIntervals)
{
// process
}
このソリューションの優れている点は、完全に延期されていることです。一度に1行ずつ処理するため、メモリ不足の例外の危険なしに無限に大きなソースを処理できます。これは、与えられた要件を考慮すると重要なようです:
このデータは 1 週間、30 日、365 日続きます。