Как найти разницу во времени в записях даты и времени того же дня, используя лямбда-выражение - PullRequest
0 голосов
/ 18 января 2020

Вот таблица, которая содержит несколько событий для активности пользователя, а также дату и время выполнения действия. Как найти разницу во времени между каждым из парных действий.

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 считается недействительным.

Выход будет выглядеть как

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

Ответы [ 2 ]

1 голос
/ 18 января 2020

Я сомневаюсь, что использование выражения Lambda является лучшим решением здесь. В соответствии с вашими требованиями вам нужно пропустить сироту INs, и это дополнительный уровень сложности, который может потребовать дополнительных поисков в вашем списке. Будет гораздо эффективнее иметь один l oop с логами c внутри, который будет просто сравнивать текущий и следующий элемент:

var list = new List<Activity>
{
    new Activity { Type = "IN", Date = DateTime.Now },
    new Activity { Type = "OUT", Date = DateTime.Now.AddSeconds(15) },
    new Activity { Type = "IN", Date = DateTime.Now.AddSeconds(23) },
    new Activity { Type = "OUT", Date = DateTime.Now.AddSeconds(27) }
};

var result = new List<string>();
for (var i = 0; i < list.Count - 1; i++)
{
    var current = list[i];
    var next = list[i+1];
    if (current.Type == "OUT" || current.Type == next.Type)
    {
        continue;
    }

    var duration = next.Date - current.Date;
    result.Add($"{current.Date:yyyy-MM-dd} | {duration.Minutes:00}:{duration.Seconds:00}");
}
1 голос
/ 18 января 2020

Я, возможно, перебил этот LOL! Но я начал писать это, так что я могу также опубликовать это. Кстати, я написал это в Notepad ++ и не пытался запустить его в Visual Studio, поэтому не могу обещать, что это сработает сразу.

Общая идея заключается в том, что вы должны загрузить данные, а затем объединить свои группы в соответствии с конкретными правилами, которые вам нужны. Затем вы можете использовать Linq для получения промежутков времени между парами входов и выходов.

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;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...