用纯 LINQ 完全解决这个问题实际上是相当困难的。为了让生活更轻松,您需要编写至少一个帮助方法来允许您转换枚举。看看下面的例子。在这里,我使用了一个IEnumerable
ofTimeInterval
并有一个自定义Split
方法(用 C# 迭代器实现),它将两个元素连接在一起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
从字符串列表中提取半小时 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
}
这个解决方案的好处是它完全被推迟了。它一次处理一行,这使您可以处理不确定的大源,而不会出现任何内存不足异常的危险,考虑到您的给定要求,这似乎很重要:
这些数据会持续一周,然后是 30 天和 365 天。