首页 > 解决方案 > 如何使用 Lambda 表达式在同一天的日期时间记录中查找时差

问题描述

这是一个表格,其中包含用户活动的多个事件以及执行活动的日期和时间。我如何找到每个配对活动之间的时间差。

Activity | Datetime

IN |2019-11-12 06:45:14.1234042

OUT |2019-11-12 09:20:14.2291323

IN |2019-11-12 10:35:14.4541043

OUT |2019-11-12 19:36:14.3431042

IN |2019-11-13 09:33:14.6541045

OUT |2019-11-13 18:35:14.3441042

IN |2019-11-14 06:32:14.2361042

OUT |2019-11-14 12:23:14.2345044

IN |2019-11-14 16:24:14.3791034

IN |2019-11-15 11:10:14.2245446

OUT |2019-11-15 19:44:14.5349504

需要注意的是,在 2019 年 11 月 14 日的第二个 In 条目没有 Out 条目的情况下,可能会缺少缩减动作。在这种情况下,In 条目被视为无效。

输出看起来像

2019-11-12 | 02:35

2019-11-12 | 09:01

2019-11-13 | 09:02

2019-11-14 | 05:51

2019-11-15 | 04:01

2019-11-16 | 08:34

标签: c#linqlambda

解决方案


我可能在这个 LOL 上矫枉过正了!但是我开始写了,所以我不妨把它贴出来。顺便说一句,我是在 Notepad++ 中编写的,并没有尝试在 Visual Studio 中运行它,所以我不能保证它会立即运行。

一般的想法是您必须加载数据,然后您必须根据您需要的特定规则配对您的组。然后,您可以使用 Linq 获取 IN 和 OUT 对之间的时间跨度。

namespace SODemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //Load the data
            List<ActivityTime> activities = ReadInActivityTimes();

            //Trying to do a lambda on the activities list would be out of scope
            // for a normal use of a Linq query. Because each item requires knowledge of the
            // next item in the list. So there needs to be a step where the related pairs are grouped.
            List<ActivityTimePair> pairs = CreatePairs(activities);

            //Now we can run a Linq query. 
            List<TimeSpan> output = pairs
                .Where(p => p.HasBoth)
                .Select(p => p.GetTimeSpan().Value)
                .ToList();

            output.ForEach(ts => 
            {
                Console.WriteLine(ts.ToString());
            });
        }

        static List<ActivityTime> ReadInActivityTimes()
        {
            return new List<ActivityTime>() {
                new ActivityTime() { Activity = "IN", TimeStamp = DateTime.Parse("2019-11-12 06:45:14.1234042" },
                new ActivityTime() { Activity = "OUT", TimeStamp = DateTime.Parse("2019-11-12 09:20:14.2291323" },
                new ActivityTime() { Activity = "IN", TimeStamp = DateTime.Parse("2019-11-12 10:35:14.4541043" },
                new ActivityTime() { Activity = "OUT", TimeStamp = DateTime.Parse("2019-11-12 19:36:14.3431042" },
                new ActivityTime() { Activity = "IN", TimeStamp = DateTime.Parse("2019-11-13 09:33:14.6541045" },
                new ActivityTime() { Activity = "OUT", TimeStamp = DateTime.Parse("2019-11-13 18:35:14.3441042" },
                new ActivityTime() { Activity = "IN", TimeStamp = DateTime.Parse("2019-11-14 06:32:14.2361042" },
                new ActivityTime() { Activity = "OUT", TimeStamp = DateTime.Parse("2019-11-14 12:23:14.2345044" },
                new ActivityTime() { Activity = "IN", TimeStamp = DateTime.Parse("2019-11-14 16:24:14.3791034" },
                new ActivityTime() { Activity = "IN", TimeStamp = DateTime.Parse("2019-11-15 11:10:14.2245446" },
                new ActivityTime() { Activity = "OUT", TimeStamp = DateTime.Parse("2019-11-15 19:44:14.5349504" }
            };
        }

        static List<ActivityTimePair> CreatePairs(List<ActivityTime> activities)
        {
            List<ActivityTimePair> pairs = new List<ActivityTimePair>();

            for (int i = 0; i < activities.Count; i++)
            {
                if (pairs.Count == 0) //first one
                {
                    pairs.Add(new ActivityTimePair());
                }

                if (activities[i].Activity == "IN")
                {
                    //If the last pair has an OUT, then we need a new pair
                    if (pairs.Last().OUT != null)
                    {
                        pairs.Add(new ActivityTimePair() { IN = activities[i]});
                    }
                    //handle case where there are 2 IN's in a row
                    else if (pairs.Last().IN != null) 
                    {
                        //Means there is 2 INs in a row
                        pairs.Add(new ActivityTimePair() { IN = activities[i]});
                    }
                    else 
                    {
                        pairs.Last().IN = activities[i];
                    }
                }

                if (activities[i].Activity == "OUT")
                {
                    //If the last pair has an OUT, there are 2 OUT's in a row
                    if (pairs.Last().OUT != null)
                    {
                        //Means there is 2 OUTs in a row
                        pairs.Add(new ActivityTimePair() { OUT = activities[i]});
                    }
                    else if (pairs.Last().IN != null) 
                    {
                        pairs.Last().OUT = activities[i];
                    }
                    //handle case where we need a new pair
                    else 
                    {
                        pairs.Add(new ActivityTimePair() { OUT = activities[i]});
                    }
                }
            }

            return pairs;
        }
    }

    class ActivityTime
    {
        public string Activity { get; set; }
        public DateTime TimeStamp { get; set; }
    }

    class ActivityTimePair
    {
        public ActivityTime IN { get; set; }
        public ActivityTime OUT { get; set; }

        public bool HasBoth 
        {
            get
            {
                return IN != null && OUT != null;
            }
        }

        public TimeSpan? GetTimeSpan()
        {
            if (HasBoth)
            {
                return OUT.TimeStamp.Subtract(IN.TimeStamp);
            }
            else 
            {
                return null;
            }
        }
    }
}

推荐阅读