2016-04-07 6 views
3

Ich frage eine Datentabelle ab und ich halte mich fest, wenn ich eine Gruppe von Gruppen auswähle.Geben Sie die ersten x Elemente in einer Gruppe von Gruppen ein

Dieser Code

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); 

Gruppen durch Zeitstempel und gibt eine Gruppe von x-Kurven, wobei x = curveid.Count(). Es enthält 5000 Gruppen.

jedoch für jeden Tag kann es mehr als ein Zeitstempel sein.

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

sagt mir, dass es 255 deutliche Tage sind.

Ich möchte nun zu einer Gruppe diese wieder, aber nicht durch Zeitstempel, sondern von Kalendertag und dann die erste (wie in frühesten) Gruppe für jeden Tag. Ich probierte folgendes:

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

aber das gibt nur 4 Gruppen zurück und ich verstehe warum nicht? Es sollte 255 Gruppen zurückgeben, von denen jede den gleichen Zeitstempel und x cureids enthält, also x * 255 Datensätze.

Die Datentabelle hat drei Spalten, Zeitstempel (Datetime), CurveID (kurz), Preis (double).

UPDATE

Wie von Herrn Skeet ein vollständiges Beispiel angefordert:

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

ich das Zufallselement entfernt und weiter vereinfacht:

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(); 
} 

Das erwartete Ergebnis ist:

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

Es wäre einfacher, sowohl die Frage zu verstehen als auch Ihnen zu helfen, wenn Sie ein kurzes aber vollständiges Beispiel liefern könnten, das das Problem demonstriert. (Ich würde vorschlagen, eine Liste als Quelldaten zu verwenden, mit regulären Eigenschaften, anstatt einer 'DataTable' ...) –

+0

Ich werde Beispieldaten hinzufügen, aber die Daten kommen aus einer Datenbank und ich lade sie mit sqladapter, so dass es endet in einer Datentabelle – nik

+0

Ja, es endet in einer 'DataTable' in Ihrem echten Code - aber Sie sollten das Problem auf die einfachste Weise demonstrieren. Wenn Sie nicht glauben, dass die 'DataTable' tatsächlich Teil des Problems ist, sollten Sie sie nicht einschließen, da es komplizierter ist, als nur eine' List ' zu verwenden. –

Antwort

1

Edited Antwort auf Ihrem Beispiel zu arbeiten.

Ok, bin ich Ihr Beispiel trought und einige Bugs behoben und meine Antwort. Lassen Sie uns den Code ein wenig klarstellen und kommentieren, was wo falsch gelaufen ist.

Unsere Modelle

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; } 
} 

nächste ist Funktion Testdaten werden zu generieren:

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 
    }; 
} 

und hier geht

Hauptfunktion
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); 
     } 
    } 
} 

diese Renditen erwarteten Ergebnisse.

Ihr Code ist fehlgeschlagen, weil Ihre zweite Gruppierung nicht (Take(nrcurves)) Werte in Gruppen nimmt aber Gruppen selbst. Anstatt also 255 Gruppen mit jeweils 2 Werten zurückzugeben, gibt man 2 Gruppen mit allen Werten zurück.

Hoffe das behebt Ihr Problem.

+0

das funktioniert nicht Ich habe Angst – nik

+0

Ich räumte ein bisschen meine Antwort. Ich verwende anonyme Objekte, aber mein Vorschlag wäre, einfache Modelle zu erstellen und mit ihnen zu arbeiten. – gzaxx

+0

funktioniert immer noch nicht ganz. Bitte sehen Sie die aktualisierte Frage – nik

Verwandte Themen