группа linq по времени начала до времени окончания в столбце DateTime

Хорошо, это довольно беспорядочный запрос, и у меня только ограниченный успех. У меня есть список класса Foo, который имеет свойство datetime и другие данные. У меня есть класс/строка почти каждую минуту, некоторые отсутствуют, а некоторые дни отсутствуют, например, праздники или выходные. Моя цель - группировать каждый день для всех строк от времени начала до времени окончания.

Так что в некоторые дни мое время начала может быть 9:30 утра и время окончания 15:00. Эту ситуацию я решаю следующим образом:

DateTime sd = new DateTime(2000, 1, 1, 9, 30, 0);
DateTime ed = new DateTime(2000, 1, 1, 15, 0, 0);
var z = Foos.Where(a=> a.FooDate.TimeOfDay >= sd.TimeOfDay &&
    a.FooDate.TimeOfDay < ed.TimeOfDay)
    .GroupBy(a=>a.FooDate.Date);

Это прекрасно работает. Моя проблема в том, что иногда у меня есть время начала 9 вечера и время окончания 6 утра. В этом случае я хочу, чтобы группа foos отправилась на ночь, и если 9 вечера в пятницу и нет строк до следующего понедельника, я хочу, чтобы группа охватила выходные. Я был бы даже рад предложению запроса, который всегда переходил бы на следующий день.

Я надеюсь, что это ясно и ценю любые идеи. Я пробовал много других способов сделать это с помощью циклов и создания другого списка разных дат и тому подобного, но я не доволен этим.


person RBear    schedule 14.05.2009    source источник
comment
Я смущен тем, что вы пытаетесь определить. Вы пытаетесь получить количество времени между записями (Foos)? или вы считаете количество записей между двумя временами?   -  person Jeremy    schedule 14.05.2009
comment
Я пытаюсь сгруппировать список объектов foo во временном диапазоне. Таким образом, в первый день есть данные, которые будут группироваться от времени начала этого дня до следующего дня, когда есть время окончания данных. Затем в этот же день начните снова в начальное время и продолжайте.   -  person RBear    schedule 14.05.2009


Ответы (2)


В физике, сталкиваясь с относительной проблемой, они выбирают, где находится ноль. И мы тоже.

// time range expressed as an example in "absolute" terms
DateTime sd = new DateTime(2000, 1, 1, 9, 30, 0);
DateTime ed = new DateTime(2000, 1, 2, 6, 0, 0);

// time range expressed as a zero and range - "relative" terms
TimeSpan zero = sd.TimeOfDay;
TimeSpan range = ed.Subtract(sd);

 //the inputs
List<DateTime> myList = new List<DateTime>()
{
  new DateTime(2009, 1, 1, 10, 0, 0),  //group1
  new DateTime(2009, 1, 1, 17, 0, 0),  //group1
  new DateTime(2009, 1, 2, 9, 0, 0),  //this is filtered
  new DateTime(2009, 1, 2, 10, 0, 0),  //group2
  new DateTime(2009, 1, 2, 15, 0, 0),  //group2
  new DateTime(2009, 1, 3, 3, 0, 0),   //group2
  new DateTime(2009, 1, 3, 7, 0, 0),  //this is filtered
  new DateTime(2009, 1, 3, 10, 0, 0)   //group3
};

  //at last, the query.
var query = myList
  .Where(d => d.Subtract(zero).TimeOfDay < range)
  .GroupBy(d => d.Subtract(zero).Date);

 //  output the results
foreach (var g in query)
{
  Console.WriteLine("{0}", g.Count());
  foreach (var d in g)
  {
    Console.WriteLine("  {0}", d);
  }
}

Результаты:

2
  1/1/2009 10:00:00 AM
  1/1/2009 5:00:00 PM
3
  1/2/2009 10:00:00 AM
  1/2/2009 3:00:00 PM
  1/3/2009 3:00:00 AM
1
  1/3/2009 10:00:00 AM
person Amy B    schedule 14.05.2009
comment
УХ ТЫ! Это как раз то, что я ищу. Это будет работать и в моем обычном случае. Спасибо много! - person RBear; 14.05.2009

Это сработает, но может быть не красивее того, что вы уже делаете.

    private List<groupFoo> groupFoos(List<foo> foos)
    {

        //Group by Day into groupFoo
        var z = foos.GroupBy(a => a.FooDate.ToShortDateString()).Select(x => new groupFoo() { Key = x.Key, Start = x.First().FooDate, End = x.Last().FooDate }).ToList();


        //Create new list to hold groups
        var groupedFoos = new List<groupFoo>();

        //add all the good groups to the list
        groupedFoos.AddRange(z.FindAll(zz => zz.Start.CompareTo(zz.End) != 0));

        //Remove all of the good groups from the orignal list
        groupedFoos.ForEach(gf => z.RemoveAt(z.IndexOf(gf)));

        //Sort whats left
        z.Sort((a, b) => { return a.Start.CompareTo(b.Start); });

        while (z.Count > 1)
        {
            //grab the first 2 
            var y = z.Take(2);

            //create a new group foo and add it to the good list
            groupedFoos.Add(y.Aggregate((a, b) => new groupFoo() { Key = a.Key, Start = a.Start, End = b.End }));

            //remove the bad ones
            y.ToList().ForEach(yy => z.RemoveAt(z.IndexOf(yy)));


        }

        return groupedFoos;
    }

и groupFoo выглядит так

public class groupFoo
{

    public string Key { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

}

образец, который я использовал

        List<foo> foos = new List<foo>();

        foos.Add(new foo() { FooDate = new DateTime(2009, 1, 1, 9, 0, 0) });
        foos.Add(new foo() { FooDate = new DateTime(2009, 1, 1, 17, 0, 0) });
        foos.Add(new foo() { FooDate = new DateTime(2009, 1, 2, 9, 30, 0) });
        foos.Add(new foo() { FooDate = new DateTime(2009, 1, 3, 6, 0, 0) });
        foos.Add(new foo() { FooDate = new DateTime(2009, 1, 4, 9, 0, 0) });
        foos.Add(new foo() { FooDate = new DateTime(2009, 1, 4, 21, 0, 0) });
person Jeremy    schedule 14.05.2009