0

我有一个看起来像这样的文件(列表已排序):

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 或其他一些可以比使用循环更快/更清洁的方法来实现吗?

4

7 回答 7

7
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() });
于 2013-06-10T08:20:57.080 回答
1

按日期分组,并获取每个日期的第一行和最后一行。例子:

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
于 2013-06-10T08:14:11.087 回答
0

要获取最新日期,您可以使用:

var latestDate = datetimeCollection.Max();

对于最古老的:

var oldestDate = datetimeCollection.Min();

请注意,这datetimeCollectionDateTime对象的列表/集合。

于 2013-06-10T08:08:45.787 回答
0

与此类似的东西应该可以工作。

  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()
                });
于 2013-06-10T08:10:23.260 回答
0
    static void Main(string[] args)
    {
        var dates = System.IO.File.ReadAllLines(@"C:\dates.txt").Select(o => DateTime.Parse(o));
        var res = new List<DateTime>();
        foreach (var item in (from o in dates group o by o.Date into g select g.Key))
        {
            var dummy = dates.Where(o => o.Date == item);
            res.Add(dummy.Max());
            res.Add(dummy.Min());
        }

    }
于 2013-06-10T08:13:48.577 回答
0

您可以按天对日期进行分组,然后对组内容进行排序并获取第一个和最后一个元素:

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());
        }
    }
}
于 2013-06-10T08:13:59.297 回答
0

“实现这一目标的最有效方法是什么?”

既然你说列表是排序的,那么我们可以通过一次源时间产生所需的时间。

这避免了所有其他答案的分组。如果输入数据未排序,则这种分组是必要的,但由于它按日期/时间升序排序的,因此我们不需要显式分组。

首先,让我们定义一个简单的转换器来将字符串转换为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;
}
于 2013-06-10T08:51:49.320 回答