“实现这一目标的最有效方法是什么?”
既然你说列表是排序的,那么我们可以通过一次源时间产生所需的时间。
这避免了所有其他答案的分组。如果输入数据未排序,则这种分组是必要的,但由于它是按日期/时间升序排序的,因此我们不需要显式分组。
首先,让我们定义一个简单的转换器来将字符串转换为DateTime
:
public IEnumerable<DateTime> ParseTimes(IEnumerable<string> times)
{
return times.Select(time => DateTime.ParseExact(time, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
}
然后我们可以编写一个简单的方法,返回每天的第一个和最后一个时间(如果当天只有一个时间,则返回一天的唯一时间),如下所示:
public IEnumerable<DateTime> FirstAndLastTimesForEachDay(IEnumerable<DateTime> times)
{
DateTime previous = DateTime.MinValue;
DateTime current = DateTime.MinValue;
foreach (var time in times)
{
if (previous.Date < time.Date)
{
if (previous != current)
yield return previous;
yield return time;
current = time;
}
previous = time;
}
if (previous != current)
yield return previous;
}
然后你可以像这样使用它:
var times = new []
{
"2013-05-02 07:45:15",
"2013-05-02 09:25:01",
"2013-05-02 18:15:15",
"2013-05-03 12:34:45",
"2013-05-04 08:45:15",
"2013-05-04 17:45:35",
"2013-05-05 20:00:00"
};
foreach (var time in FirstAndLastTimesForEachDay(ParseTimes(times)))
Console.WriteLine(time);
请注意,上面的实现仅在仅包含单个 DateTime 的日子中输出单个 DateTime。相反,如果您希望输出包含一天中单次出现的 DateTime 的两倍(因此即使时间相同,您每天也总是有一对 DateTime),则将实现更改为:
public IEnumerable<DateTime> FirstAndLastTimesForEachDay(IEnumerable<DateTime> times)
{
DateTime previous = DateTime.MinValue;
foreach (var time in times)
{
if (previous.Date < time.Date)
{
if (previous != DateTime.MinValue)
yield return previous;
yield return time;
}
previous = time;
}
if (previous != DateTime.MinValue)
yield return previous;
}