2016-04-07 3 views
3

Я запрашиваю данные, и я, похоже, придерживаюсь выбора группы групп.Возврат первых элементов x в группе групп

Этот код

var grouping = table.AsEnumerable() 
       .Where(x => curveids.Contains(x.Field<short>("CurveID")) && x.Field<DateTime>("Timestamp").Hour >= hour && x.Field<DateTime>("Timestamp").Hour < (hour + 1)) 
       .GroupBy(x => x.Field<DateTime>("Timestamp")).Where(x => x.Select(y => y["CurveID"]).Count() == curveids.Count); 

группы по временной метки и возвращает группу кривых х, где х = curveid.Count(). Он содержит 5000 групп.

Однако на каждый день может быть более одной отметки времени.

int nrdays = grouping.GroupBy(z => z.Key.Date).Count(); 

говорит, что есть 255 отдельных дней.

Теперь я хотел бы сгруппировать это, но не по времени, а по календарному дню, а затем взять первую (как раньше) группу за каждый день. Я пробовал:

var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(curveids.Count); 

но это только возвращает 4 группы, и я не понимаю почему? Он должен возвращать 255 групп, каждый из которых содержит одну и ту же метку времени и x кривые, поэтому x * 255 наборов записей.

В datatable есть 3 столбца, временная метка (DateTime), криваяID (короткая), цена (двойная).

ОБНОВЛЕНИЕ

В соответствии с просьбой г-н тарелочкам полный пример:

public class listprx 
    { 
     public DateTime timestamp; 
     public int curveID; 
     public double prx; 
    } 

    static void Main(string[] args) 
    { 
     var data = new List<listprx>(); 

     // populating data 
     for (int i = 0; i < 50000; i++) 
     { 
      Random rand = new Random(i); 
      var tempdt = new DateTime(2016, rand.Next(1, 12), rand.Next(1, 29), rand.Next(1, 23), rand.Next(1, 59), 0); 

      if(i % 3 == 0) 
      { 
       data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1,50)}); 
       data.Add(new listprx { timestamp = tempdt, curveID = 2, prx = rand.Next(1, 50) }); 
      } 
      else if (i % 5 == 0) 
      { 
       data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1, 50) }); 
      } 
      else 
      { 
       data.Add(new listprx { timestamp = tempdt, curveID = 1, prx = rand.Next(1, 50) }); 
       data.Add(new listprx { timestamp = tempdt, curveID = 2, prx = rand.Next(1, 50) }); 
       data.Add(new listprx { timestamp = tempdt, curveID = 3, prx = rand.Next(1, 50) }); 
      } 
     } 

     // setting hour criteria 
     int hour = 16; 
     int nrcurves = 3; 

     // grouping by timestamp and only take those where all curves are there, (as close to the desired time as possible 
     var grouping = data.Where(x => x.timestamp.Hour >= hour && x.timestamp.Hour < (hour + 1)) 
      .GroupBy(x => x.timestamp).Where(x => x.Select(y => y.curveID).Count() == nrcurves); 

     // Grouping by day and take only the time stamp that is closest to the hour 
     // this fails 
     var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(nrcurves); 

     Console.WriteLine("Nr of timestamps with all curves {0}, nr of days {1}, nr of groups in second group {2}, expected same as nr days" 
      , grouping.Count(), grouping.GroupBy(z => z.Key.Date).Count(), grouping2.Count()); 

     Console.ReadLine(); 
} 

UPDATE 2

Я удалил случайный элемент и упрощен далее:

public class listprx 
{ 
     public DateTime timestamp; 
     public int curveID; 
} 

static void Main(string[] args) 
{ 
     var data = new List<listprx>(); 

     // populating data 
     var tempdt = new DateTime(2016, 4, 6, 16, 1, 0); 

     for (int i = 0; i < 4; i++) 
     { 
      if (i == 2) 
      { 
       tempdt = tempdt.AddDays(1); 
      } 

      if(i % 2 == 0) 
      { 
       data.Add(new listprx { timestamp = tempdt, curveID = 1}); 
      } 
      else 
      { 
       data.Add(new listprx { timestamp = tempdt, curveID = 1}); 
       data.Add(new listprx { timestamp = tempdt, curveID = 2}); 
      } 

      tempdt = tempdt.AddMinutes(i+1); 
     } 

     // setting hour criteria 
     int hour = 16; 
     int nrcurves = 2; 

     //grouping by timestamp and only take those where all curves are there, (as close to the desired time as possible 
     var grouping = data.Where(x => x.timestamp.Hour >= hour && x.timestamp.Hour < (hour + 1)) 
      .GroupBy(x => x.timestamp).Where(x => x.Select(y => y.curveID).Count() == nrcurves); 

     //Grouping by day and take only the time stamp that is closest to the hour 
     //this fails 
     var grouping2 = grouping.GroupBy(z => z.Key.Date).OrderBy(a => a.Key).Take(nrcurves); 

     Console.WriteLine("Nr of timestamps with all curves {0}, nr of days {1}, nr of groups in second group {2}, expected same as nr days" 
      , grouping.Count(), grouping.GroupBy(z => z.Key.Date).Count(), grouping2.Count()); 

    Console.ReadLine(); 
} 

Ожидаемый конечный результат:

Timestamp  CurveID 
------------------------ 
6/4/16 16:02  1 
6/4/16 16:02  2 
7/4/16 16:06  1 
7/4/16 16:06  2 
+1

Было бы проще понять и ответить на вопрос, если бы вы могли предоставить короткий, но полный пример, демонстрирующий проблему. (Я бы предложил использовать список в качестве исходных данных, с регулярными свойствами, а не с 'DataTable' ...) –

+0

Я добавлю примеры данных, но данные поступают из базы данных, и я загружаю его с помощью блока sqladapter, чтобы он заканчивался в datatable – nik

+0

Да, это заканчивается в «DataTable» в вашем реальном коде, но вы должны продемонстрировать проблему самым простым способом. Если вы не считаете, что «DataTable» на самом деле является частью проблемы, вы не должны включать его, поскольку это сложнее, чем просто использовать «Список ». –

ответ

1

Отредактированный ответ работает на вашем примере.

Хорошо, я прошел ваш пример и исправил некоторые ошибки и свой ответ. Давайте немного очистим код и прокомментируем, что пошло не так.

Наши модели будут

public class Curve 
{ 
    public int CurveID { get; set; } 
    public DateTime Timestamp { get; set; } 
} 

public class CurveGroup 
{ 
    public DateTime Timestamp { get; set; } 
    public IEnumerable<Curve> Curves { get; set; } 
} 

рядом есть функция для генерации тестовых данных:

public static List<Curve> GetData() 
{ 
    var data = new List<Curve>(); 
    var startTime = new DateTime(2016, 4, 6, 16, 1, 0); 

    for (int i = 0; i < 4; i++) 
    { 
     if (i == 2) 
     { 
      //startTime.AddDays(1); - this line does nothing, DateTime is an immutable struct so all function changing its value returns a new copy 
      startTime = startTime.AddDays(1); 
     } 

     if (i % 2 == 0) 
     { 
      data.Add(CreateNewCurve(startTime, 1)); 
     } 
     else 
     { 
      data.Add(CreateNewCurve(startTime, 1)); 
      data.Add(CreateNewCurve(startTime, 2)); 
     } 

     //startTime.AddMinutes(i + 1); same issue as above 
     startTime = startTime.AddMinutes(i + 1); 
    } 

    return data; 
} 

public static Curve CreateNewCurve(DateTime time, int curveID) 
{ 
    return new Curve() 
    { 
     Timestamp = time, 
     CurveID = curveID 
    }; 
} 

и здесь идет основная функция

static void Main(string[] args) 
{ 
    var data = GetData(); 

    int hour = 16; 
    int totalCurveCount = 2; 

    var grouping = data 
      .Where(x => x.Timestamp.Hour >= hour && x.Timestamp.Hour < (hour + 1)) 
      .GroupBy(x => x.Timestamp) 
      .Where(x => x.Count() == totalCurveCount); //there is no need to select curveId like in your code: Where(x => x.Select(y => y.curveID).Count() == nrcurves); 

    var grouping2 = grouping 
      .GroupBy(x => x.Key.Date) 
      .Select(x => 
       new CurveGroup 
       { 
        Timestamp = x.Key, 
        Curves = x.OrderBy(c => c.Key).Take(totalCurveCount).SelectMany(c => c) 
       } 
      ); 


    foreach (var g in grouping2) 
    { 
     foreach (var c in g.Curves) 
     { 
      Console.WriteLine(c.Timestamp); 
      Console.WriteLine(c.CurveID); 
     } 
    } 
} 

это ожидаемые результаты возвращения.

Ваш код не удался, потому что ваша вторая группировка не принимает значения (Take(nrcurves)) в группах, кроме групп. Поэтому вместо того, чтобы возвращать 255 групп с двумя значениями в каждом, вы возвращаете 2 группы со всеми значениями в них.

Надеюсь, что эта проблема решена.

+0

это не работает Я боюсь – nik

+0

Я немного расчел свой ответ. Я использую анонимные объекты, но мое предложение было бы создать простые модели и работать с ними. – gzaxx

+0

все еще не работает. PLS см. обновленный вопрос – nik

Смежные вопросы