2012-04-03 13 views
3

Ich habe eine große Datentabelle (500k-1m Reihen), ohne ins Detail zu gehen dies ist eine Voraussetzung, wie der Endbenutzer alle Daten sehen kann/will. Dies ist auf einem lokalen Server, so dass Bandbreite usw. keine Sorgen für mich sind.Group DateTime Zeilen in Datentabelle von DateTime - C#

Ich habe ein DateTime-Feld in der DataTable, die ich gruppieren muss, lassen Sie mich erklären, was ich meine mit Gruppierung ... Es ist wahrscheinlich nicht das, was Sie meine ich meine (aus dem Blick auf die anderen Fragen hier!).

 var table = new DataTable(); 
     table.Columns.Add("EventTime", typeof(DateTime)); 
     table.Columns.Add("Result", typeof(String)); 
     table.Columns.Add("ValueOne", typeof(Int32)); 
     table.Columns.Add("ValueTwo", typeof(Int32)); 
     table.Rows.Add("2012-02-06 12:41:45.190", "A", "7", "0"); 
     table.Rows.Add("2012-02-06 12:45:41.190", "B", "3", "89"); 
     table.Rows.Add("2012-02-06 12:59:41.190", "C", "1", "0"); 
     table.Rows.Add("2012-02-06 13:41:41.190", "D", "0", "28"); 
     table.Rows.Add("2012-02-06 17:41:41.190", "E", "0", "37"); 
     table.Rows.Add("2012-02-07 12:41:45.190", "F", "48", "23"); 

Ich würde erwarten, dass die obige Tabelle gruppiert werden, so dass ich eine Summe der „valueOne“ Spalte und ein Durchschnitt des „valueTwo“ -Spalte zu bekommen. Ich brauche die Gruppierung, um ein wenig flexibel zu sein, so dass ich angeben kann, dass ich nach Minuten gruppieren möchte (nur die erste und letzte Zeile würden gruppiert werden, der Rest würde nur ihre Werte liefern), oder nach Tagen (alle außer der letzten Zeile würde in einer einzigen Reihe gruppiert werden), usw.

Ich habe das ein paar Mal versucht, aber ich bekomme keine wo. Mein LINQ-Wissen ist nicht großartig, aber ich dachte, ich könnte das tun!

Hinweis: Die DataTable befindet sich bereits auf der Maschine für Berechnungen/Ansichten, die nicht geändert werden können, also sag "Hör auf, ein Idiot zu sein, filtere in SQL !!!" ist eine gültige Antwort, nur nutzlos für mich! :-D

auch, falls Sie es im Titel verpasst, muss ich dies in C# - Ich arbeite mit .NET 4.0 ...

Vielen Dank im Voraus, Ihnen zu helfen, unter der Annahme entscheiden! :-)

+0

Auch wenn Sie die Daten bereits lokal geladen haben und sich nicht um die Leistung kümmern, sollten Sie darauf hinweisen, dass das Ausführen einer LINQ-Abfrage für einen Linq-to-SQL- oder Entity-Kontext aus Codesicht viel einfacher ist . – StriplingWarrior

+0

@StriplingWarrior: Warum ist eine LINQ-To-SQL-Abfrage einfacher als eine LINQ-To-DataSet-Abfrage? –

+0

@TimSchmelter: Da Datasets keine zur Kompilierungszeit bekannte Struktur haben. Sie müssen Verrenkungen durchführen, um Werte zu konvertieren und Indexer zu verwenden, anstatt nur die Syntax zum Generieren von Eigenschaften zu verwenden. – StriplingWarrior

Antwort

4

Die anderen drei Die Antworten sind nahe, aber wie Sie darauf hingewiesen haben, gruppieren sie Ereignisse, die in der gleichen Sekunde der Minute aufgetreten sind, und nicht Ereignisse, die in derselben Sekunde geschehen, was Sie wollen. Versuchen Sie Folgendes:

Sie können anpassen, welche Informationen an den DateTime-Konstruktor übergeben werden, um sie nach unterschiedlichen Zeitabschnitten zu gruppieren.

+0

Nur um klar zu sein, sagst du, dass ihre Antworten 03/04/2012 10:00:01 mit gruppieren werden 11/10/2099 10:00:01? – Faraday

+0

Ich bekomme "Kann das Symbol nicht lösen lassen" - Any Ideen, bitte mit mir ertragen .. Ich bin nur ein Anfänger! :) – Faraday

+1

Ja das ist, was ich sage. –

1

Die einzige Sache, die Sie ändern müssen, ist die Eigenschaft, die Sie gruppieren möchten.

var query = from x in DataSource 
      group x by x.EventTime.Minute into x 
      select new 
      { 
       Unit = x.Key, 
       SumValueOne = x.Sum(y => y.ValueOne), 
       AverageValueTwo = x.Average(y => y.ValueTwo), 
      }; 
+0

Ich mag das Aussehen dieser Antwort wirklich ... Ich schneide es einfach in visual Studio, um genau zu sehen, was Sie getan haben, und es mag nicht, dass DataSource eine DataTable ist, und wenn ich DataTable.Rows schreibe, dann beschwert es sich Mehr! Hoffentlich weißt du, was ich meine ... – Faraday

1

So etwas sollte funktionieren:

DataTable dt = GetDataTableResults(); 

var results = from row in dt.AsEnumerable() 
       group row by new { EventDate = row.Field<DateTime>("EventTime").Date } into rowgroup 
       select new 
       { 
        EventDate = rowgroup.Key.EventDate, 
        ValueOne = rowgroup.Sum(r => r.Field<int>("ValueOne")), 
        ValueTwo = rowgroup.Average(r => r.Field<decimal>("ValueTwo")) 
       }; 
+0

Ich vermisse wahrscheinlich etwas sehr offensichtlich, aber woher weiß es, welchen Teil der Datetime zu gruppieren? – Faraday

+0

Nun, in diesem Beispiel gruppiert es nur das Datum und ignoriert die Zeit. Wenn Sie andere Gruppierungskriterien benötigen, können Sie 'row.Field (" EventTime "). Date' ändern, was immer Sie brauchen. –

+0

Würde dies nicht das Jahr/den Monat/Tag ignorieren und einfach sagen: "Der zweite ist der gleiche, also werde ich ihn gruppieren", wenn ich mich für die zweite Gruppierung entscheide? Oder berücksichtigt es auch die anderen Bereiche? – Faraday

0

Hier ist, was Ihr Code Baseline aussehen könnte:

var query = table.Rows.Cast<DataRow>() 
    .GroupBy(r => ((DateTime)r[0]).Second) 
    .Select(g => new 
       { 
        g.Key, 
        Sum = g.Sum(r => (int)r[2]), 
        Average = g.Average(r => (int)r[3]) 
       }); 

Flexibilität hinzuzufügen, Sie so etwas wie dieses haben könnte:

IEnumerable<IGrouping<object, DataRow>> Group(IEnumerable<DataRow> rows, GroupType groupType) 
{ 
    // switch case would be preferable, but you get the idea. 
    if(groupType == GroupType.Minutes) return rows.GroupBy(r => ((object)((DateTime)r[0]).Minute)); 
    if(groupType == GroupType.Seconds) return rows.GroupBy(r => ((object)((DateTime)r[0]).Second)); 
    ... 
} 

var baseQuery = table.Rows.Cast<DataRow>(); 
var grouped = Group(baseQuery, groupType); 
var query = grouped 
    .Select(g => new 
       { 
        g.Key, 
        Sum = g.Sum(r => (int)r[2]), 
        Average = g.Average(r => (int)r[3]) 
       }); 
+0

Würde das nicht die anderen Teile des Datums vollständig ignorieren? – Faraday

+0

Was ich meine ist, würde dies nicht den Tag ignorieren und einfach sagen "Der zweite ist der gleiche, also werde ich ihn gruppieren"? Außerdem denke ich nicht, dass dies die "LINQ-Abfrage gegen einen Linq-to-SQL- oder Entitätskontext" ist, die Sie vorgeschlagen haben ... – Faraday

+0

@ user1311339: Das war nur dazu gedacht, Ihnen eine Vorstellung davon zu geben, wo Sie anfangen sollen. Siehe mein Update für, wie man ändert, was Sie gruppieren, basierend auf einem Argument. – StriplingWarrior