C# C查找日期范围内的第一次和最后一次日期
我有一个文件,看起来如下列表所示:C# C查找日期范围内的第一次和最后一次日期,c#,datetime,find,C#,Datetime,Find,我有一个文件,看起来如下列表所示: 2013-05-02 07:45:15 2013-05-02 09:25:01 2013-05-02 18:15:15 2013-05-04 08:45:15 2013-05-04 17:45:35 我只想得到列表中每天的第一次和最后一次,所以这意味着我想得到: 2013-05-02 07:45:15 2013-05-02 18:15:15 2013-05-04 08:45:15 2013-05-04 17:45:35 实现这一目标最有效的方法是什么? 我
2013-05-02 07:45:15
2013-05-02 09:25:01
2013-05-02 18:15:15
2013-05-04 08:45:15
2013-05-04 17:45:35
我只想得到列表中每天的第一次和最后一次,所以这意味着我想得到:
2013-05-02 07:45:15
2013-05-02 18:15:15
2013-05-04 08:45:15
2013-05-04 17:45:35
实现这一目标最有效的方法是什么?
我想我将能够得到这个使用周期,并在其中比较日期。但也许有更有效的方法?这可以通过使用linq或其他比使用cycles更快/更干净的方法来实现吗?要获取最新日期,您可以使用:
var latestDate = datetimeCollection.Max();
对于最老的一个:
var oldestDate = datetimeCollection.Min();
请注意,datetimeCollection是DateTime对象的列表/集合。类似于此的东西应该可以工作
var allDates = new[]
{
"2013-05-02 07:45:15",
"2013-05-02 09:25:01",
"2013-05-02 18:15:15",
"2013-05-04 08:45:15",
"2013-05-04 17:45:35"
};
var earliest = allDates.GroupBy(date => Convert.ToDateTime(date).Day).Select(g => new
{
first = g.Min(),
last = g.Max()
});
您可以按天对日期进行分组,然后对组内容进行排序,并获取第一个和最后一个元素:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
class Program {
static void Main(string[] args) {
string[] fileContents = new string[] {
"2013-05-02 07:45:15",
"2013-05-02 09:25:01",
"2013-05-02 18:15:15",
"2013-05-04 08:45:15",
"2013-05-04 17:45:35"
};
List<DateTime> dates = fileContents.ToList().ConvertAll(s => DateTime.ParseExact(s, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
foreach (var datesInSameDay in dates.GroupBy(d => d.Day)) {
var datesList = datesInSameDay.ToList();
datesList.Sort();
Console.WriteLine(datesList.First());
Console.WriteLine(datesList.Last());
}
}
}
按日期分组,并获取每个日期的第一行和最后一行。例如:
string[] dates = {
"2013-05-02 07:45:15",
"2013-05-02 09:25:01",
"2013-05-02 18:15:15",
"2013-05-04 08:45:15",
"2013-05-04 17:45:35"
};
var days =
dates.GroupBy(s => s.Substring(0, 10))
.Select(g => new { First = g.First(), Last = g.Last() });
foreach (var day in days) {
Console.WriteLine("{0} - {1}", day.First, day.Last);
}
输出:
2013-05-02 07:45:15 - 2013-05-02 18:15:15
2013-05-04 08:45:15 - 2013-05-04 17:45:35
实现这一目标最有效的方法是什么
既然您说列表已排序,那么我们就可以通过一次传递源时间来生成所需的时间
这避免了由所有其他答案进行分组。如果输入数据未排序,则需要进行这样的分组,但因为它是按升序日期/时间排序的,所以不需要显式分组
首先,让我们定义一个简单的转换器,将字符串转换为DateTime:
请注意,上面的实现只输出一个DateTime for days,其中只包含一个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;
}
这只会得到整个列表的第一个和最后一个,而不是每天的第一个和最后一个。没有日期转换,我喜欢它:为什么要投否决票?如果您不解释您认为错误的地方,则无法改进答案。由于列表已排序,使用“最小”和“最大”来获取最低和最高值只是浪费时间,只需使用“第一”和“最后”。您已经在组中找到了日期,您不需要在每个组的集合中找到日期。是的,如果没有这一点,它将与@cuongle-answer一样是最好的答案
var result = File.ReadAllLines("yourPath")
.Select(line => DateTime.ParseExact(line,
"yyyy-MM-dd HH:mm:ss",
CultureInfo.CurrentCulture))
.GroupBy(d => d.Date)
.SelectMany(g => new[] { g.Min(), g.Max() });
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);
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;
}