Problem mit dem korrekten Durchlaufen einer Tabelle

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von dattKlobiche.

    Problem mit dem korrekten Durchlaufen einer Tabelle

    Moin zusammen,

    ich habe eine Tabelle mit 2 Spalten. Die erste Spalte ist das Datum inklusive Uhrzeit, die zweite die Temperatur eines Geräts.

    1.10.2015/ 7:15 |174,3
    1.10.2015/ 7:17 | 175,1
    und irgendwann dann
    2.10.2016/ 7:25 |163,5
    usw.

    Jetzt soll das Programm einmal durch alle Datensätze laufen und dabei von jedem Tag die Zeit berechnen in der die Temperatur über einem bestimmten Wert war(in diesem Fall 175°C). Für einen Tag funktioniert das auch prächtig, allerdings stehe ich etwas auf dem Schlauch was die äußere Schleife angeht. Leider ist die Anzahl der Messungen pro Tag auch nicht fix also kann jeder Tag unterschiedlich viele Messungen enthalten.

    VB.NET-Quellcode

    1. Dim stunden As TimeSpan
    2. Dim erster As TimeSpan
    3. Dim letzter As TimeSpan
    4. Dim stunde As Date
    5. 'Das erste Datum in der Tabelle(wird später eingegeben)
    6. Dim startdatum As Date = "01.10.2015"
    7. 'Diese Schleife müsste vernünftig durch die Tabelle laufen, im Moment funktioniert halt nur der erste Tag
    8. For i = 0 To LogsBindingSource.Count - 1
    9. Dim zeiten As New HashSet(Of TimeSpan)
    10. Dim logrow = DirectCast(DirectCast(LogsBindingSource.Item(i), DataRowView).Row, Daten.LogsRow)
    11. If logrow.Time.ToShortDateString = startdatum.AddDays(i) Then
    12. 'Ausrechnen der Stunden für den bestimmten Tag, das funktioniert
    13. For j = 0 To LogsBindingSource.Count - 1
    14. Dim logtest = DirectCast(DirectCast(LogsBindingSource.Item(j), DataRowView).Row, Daten.LogsRow)
    15. If logtest.Time.ToShortDateString = startdatum.AddDays(i) And logtest.Temp >= 175 Then
    16. Tag = logtest.Time.ToShortDateString
    17. stunde = logtest.Time.ToShortTimeString
    18. zeiten.Add(stunde.TimeOfDay)
    19. End If
    20. Next
    21. erster = zeiten.First
    22. letzter = zeiten.Last
    23. stunden = letzter - erster
    24. Daten.Stunden.AddStundenRow(logrow.Time.ToShortDateString, stunden)
    25. 'bis hier
    26. End If
    27. Next


    Ach ja, wieso das nicht klappt ist mir klar, ich find nur keine andere Lösung ;)

    Ich hoffe ich habe mich verständlich ausgedrückt ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dattKlobiche“ ()

    @dattKlobiche Wieso hast Du 2 ineinander geschachtelte Schleifen To LogsBindingSource.Count - 1?
    Du brauchst eine davon, um über alle Zeilen zu iterieren.
    Innen drin holst Du Dir ein DateTime-Objekt aus der 1. Spalte sowie ein Double für den Messwert und feddich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Weil ich nicht wusste wie ich dann in der Schleife Stunden für jeden Tag einzeln ausrechnen kann. Ich mach mir nochmal Gedanken, immerhin sind das ca 35k Datensätze und da ist es nicht verkehrt an Schleifen zu sparen.

    Edit:
    Den Messwert brauche ich ja nachher gar nicht. Ein neuer Ansatz ist:

    VB.NET-Quellcode

    1. Dim datum As New HashSet(Of Date)
    2. Dim startdatum As Date = "01.10.2015"
    3. For i = 0 To LogsBindingSource.Count - 1
    4. Dim logrow = DirectCast(DirectCast(LogsBindingSource.Item(i), DataRowView).Row, Daten.LogsRow)
    5. If logrow.Temp >= 175 Then
    6. datum.Add(logrow.Time)
    7. End If
    8. Next

    Dann könnte ich die Zeiten von jedem Tag in ein Hashset packen, wie oben berechnen und das Ergebnis in die Bindingsource zusammen mit dem Datum eintragen. Jetzt muss ich nur noch die Ideen im Kopf umsetzen ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dattKlobiche“ ()

    dattKlobiche schrieb:

    da ist es nicht verkehrt an Schleifen zu sparen
    Das ist grundverkehrt :!:
    Was sollte denn in den vielen Schleifen passieren?
    Fang mitv einem ordentlichen Plan an.
    Mach Dir zuerst eine Konvertierung Deines Zeitstempels in ein DateTime-Objekt:

    VB.NET-Quellcode

    1. Dim dat = "1.10.2015/ 7:15"
    2. Dim parts() = dat.Split(New Char() {"/"c}, StringSplitOptions.RemoveEmptyEntries)
    3. Dim datum() = parts(0).Split(New Char() {"."c}, StringSplitOptions.RemoveEmptyEntries)
    4. Dim zeit() = parts(1).Split(New Char() {":"c}, StringSplitOptions.RemoveEmptyEntries)
    5. Dim dt = New DateTime(CInt(datum(2)), CInt(datum(1)), CInt(datum(0)), CInt(zeit(0)), CInt(zeit(1)), 0)
    6. MessageBox.Show(dt.ToString)
    den Rest solltest Du allein schaffen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Der Zeitstempel steht als DateTime in der Tabelle. Oben war das nur beispielhaft dargestellt. Mein Code nutzt ja den ganzen DateTime Krempel schon.
    Ich stell mir das auch eigentlich ganz einfach vor.
    Die Schleife läuft durch die Bindingsource und packt alle Zeitstempel bei denen die Temperatur >= 175 ist in eine Liste(HashSet z.B.). Dann brauche ich ja im Prinzip nur die Liste durchlaufen, mir einen Tag raussuchen und dann die erste Uhrzeit(die an dem Tag geloggt wurde) von der letzten abziehen. Das kommt dann zusammen mit dem Tag in die neue Tabelle.
    Dann müsste er mit dem nächsten Tag weitermachen(deswegen oben Startdatum.AddDays(i)). Klingt in meinem Kopf ganz einfach und ist es wahrscheinlich auch.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dattKlobiche“ ()

    RodFromGermany schrieb:

    Mach Dir zuerst eine Konvertierung Deines Zeitstempels in ein DateTime-Objekt

    Das ist immer eine gute Idee. Ich würde es allerdings mit DateTime.TryParse machen.
    Hie ein Beispiel zum Test:

    C#-Quellcode

    1. string input = "1.10.2015/ 7:15";
    2. DateTime dateTime;
    3. if (DateTime.TryParse(input.Replace("/",""), out dateTime))
    4. {
    5. Console.WriteLine(dateTime);
    6. }

    Und was die ganze Auswertung angeht, würde ich das auch anders machen, das muss aber auf Andere nicht zutreffen.
    Ich würde also alle Datensätze mit einem schnellen BulkUpload in meine Datenbank packen und hätte dann mit einer simplen Query alle Möglichkeiten, nach meinen Bedingungen zu suchen und passend zu gruppieren.
    Der BulkUpload dauert bei 35k Datensätzen ein Fingerschnipsen.
    @dattKlobiche Kannst Du dann bitte mal Dein Problem konkret formulieren?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    In der Tabelle gibt es zwei Spalten, einmal das Datum mit Uhrzeit der Messung und den Messwert(Temperatur). Es gibt mehrere Messungen pro Tag. Am Ende brauche ich für jeden Tag die Dauer(in Stunden und Minuten) wo die Temperatur >= 175°C ist. Das ganze kommt dann ein eine neue Tabelle und wird zur Auswertung in Excel exportiert.
    Deswegen war ich auch bei den 2 Schleifen. Eine durchläuft die Tabelle und fischt sich nacheinander die Tage raus, die nächste läuft durch und zieht aus den gefundenen Tagen die Uhrzeiten bei denen die Temperatur >= 175 ist. Daraus wird dann die Zeitspanne berechnet in welcher die Temperatur an dem Tag passend war.
    Das Problem war, dass der Code aus dem ersten Post nur den ersten Tag berechnet weil das addieren eines Tages auf das Datum nicht vernünftig funktioniert hat.

    dattKlobiche schrieb:

    Jetzt soll das Programm einmal durch alle Datensätze laufen und dabei von jedem Tag die Zeit berechnen in der die Temperatur über einem bestimmten Wert war
    Das verstehe ich - hingegen vieles andere nicht.

    Also wenns das wirklich ist, was du brauchst, dann berechne doch zunächstmal einfach alle Zeiten mit T > 175°.
    Nach Tagen gruppieren kannst du die Ergebnisse dann immer noch.

    Ich hab allerdings auch ein Problem mit den Ergebnissen - wie sollen die letztendlich aussehen?
    Willst du eine Liste der Tage, und jeder Tag enthält eine Liste der Zeiten>175° ?
    Oder willst du eine Liste der Tage, und jeder Tag gibt nur die Summe dieser Zeiten an?

    Vielleicht willst du auch eine Liste mit nur den Tagen, wo >175 auftritt?

    Wie Rod schon sagt: Sag genau, was für eine Liste bei rauskommen soll.
    Dann poste Screenshot der LogEntry-Tabelle, dann kann ich sone Funktion sehr schnell hinhauen.

    Edit: Überkreuzt.
    Übrigens die Signatur der LogRow kann ich ja auch post#3 entnehmen.
    Also ich bastel was, was einfach nur DateTimes zurückgibt.
    Davon DateTime.Date gibt den Tag an, und .TimeOfDay gibt die aufsummierte Zeit > 175

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Da brauchst Du die 1. und die letzte Temperatur, die größer ist.
    Dieese beiden Werte packst Du in eine Zeile einer neuen Tabelle, da kannst Du auch gleich die Dauer ausrechnen und eintragen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    ich hab jetzt was gebastelt, was zunächstmal 50 Messungen generiert, alle 4h. Per PseudoZufall ist jede 10. > 175°.
    Wie gesagt, die Ergebnis-Liste beinhaltet nur DateTimes, nur von Dates mit Hitze, und deren TimeOfDay gibt die Dauer-Summe an.
    Wobei ich einfach annehme, dass eine Hitze-Messung eine Hitze-Zeitspanne bis zur nächsten Messung bedeutet

    VB.NET-Quellcode

    1. Private Sub Test()
    2. Dim rnd = New Random(99)
    3. Dim logrows = Enumerable.Range(0, 50).Select(Function(i) CreateLogRow(i, rnd)).ToList
    4. Dim hotDayTimes = GetHotDayTimes(logrows).ToList
    5. End Sub
    6. Private Function CreateLogRow(i As Integer, rnd As Random) As LogRow
    7. Dim time = Date.Today.AddHours(1 + i * 4) 'ergibt 6 Messungen - um 1, 5, 9, 13, 17, 21 Uhr
    8. Dim temp = If(rnd.NextDouble() < 0.1, 180, 99) 'ergibt in 10% der Fälle 180°
    9. Return New LogRow With {.Temp = temp, .Time = time}
    10. End Function
    11. Private Function GetHotDayTimes(logRows As IEnumerable(Of LogRow)) As IEnumerable(Of DateTime)
    12. Dim hotCounts = From rw In logRows Where rw.Temp > 175 Group By rw.Time.Date Into Count()
    13. Return From hotCount In hotCounts Select hotCount.Date + TimeSpan.FromHours(hotCount.Count * 4)
    14. End Function
    15. <DebuggerDisplay("{Time.ToString(""g"")} {Temp}")> _
    16. Public Class LogRow
    17. Public Time As Date
    18. Public Temp As Double
    19. End Class
    Sowohl die generierten LogRows als auch die Ergebnisse im Haltepunkt auf zeile#5 angugge.

    Beachte, dass der 1.5 und der 2.5 inner Ergebnisliste nicht auftaucht, weil das sind "kühle Tage".

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ich weiß, macht der Code im ersten Beitrag ja auch. Aber auf die Idee mit einer extra Tabelle bin ich natürlich nicht gekommen :D. Da könnte man dann ja einfach die Bindingsource nach einem Tag filtern und die Zeiten rausholen.
    Oh jeh - der erste Beitrag:

    dattKlobiche schrieb:

    VB.NET-Quellcode

    1. Dim startdatum As Date = "01.10.2015"

    Ich dachte, sone Gurken hätteste hinter dir gelassen.



    Den Code habich übrigens garnet angeguckt, weil du schriebst, der mache nicht, was er soll.

    Na denn, alle Müh mal wieder für die Katz, weil ich nicht wusste/weiß, was eiglich das Problem ist. :(

    ErfinderDesRades schrieb:

    Oh jeh - der erste Beitrag:

    dattKlobiche schrieb:

    VB.NET-Quellcode

    1. Dim startdatum As Date = "01.10.2015"

    Ich dachte, sone Gurken hätteste hinter dir gelassen.



    Den Code habich übrigens garnet angeguckt, weil du schriebst, der mache nicht, was er soll.

    Na denn, alle Müh mal wieder für die Katz, weil ich nicht wusste/weiß, was eiglich das Problem ist. :(


    Die Gurke kommt auch noch weg. War gestern auf die Schnelle getippt zum Testen. Und für die Katz ist das mit Sicherheit nicht, die obere Variante hat ja nicht 100%ig funktioniert. Post Nr. 14 war auch an Rod gerichtet, du warst mit deinem Beitrag nur etwas eher.

    Sehe ich das richtig, dass bei deinem Code das Ergebnis im Debugger ausgegeben wird?

    Der erste Code war auch ziemlich umständlich, im Endeffekt ist es viel sinniger alle Daten mit > 175 zu suchen und in eine Liste zu packen. Dann kann man dann ja die Stunden berechnen. Und das ist doch das was dein Code macht oder nicht? Ich guck mir den jetzt mal genau an und versuch zu verstehen was passiert ;)

    Edit: Stand der Dinge ist, dass ich ein HashSet mit allen Daten habe wo die Temperatur über 175° war. Ich arbeite grad daran nacheinander die Zeitstempel für jeden Tag raus zu holen und die Stunden zu berechnen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dattKlobiche“ ()

    dattKlobiche schrieb:

    Die Gurke kommt auch noch weg. War gestern auf die Schnelle getippt zum Testen.
    Das hat mit schnell tippen nix zu tun, sondern zeigt, dass du dein Visualstudio in Anfänger-Einstellungen betreibst, die dir die Eigenschaften der Datentypen verbergen.

    Hättest du Visual Studio - Empfohlene Einstellungen umgesetzt, so könntest du tippen schnell wie wolle, und solche Gurken könnten nicht entstehen.
    Es tut jetzt was es soll, vielleicht hilft der Code ja irgendwem mal :)
    Wahrscheinlich wäre es noch sinniger das Hashset wegzulassen und die Daten direkt in die Tabelle zu schreiben, wird wohl noch geändert.

    VB.NET-Quellcode

    1. Dim datum As New HashSet(Of Date)
    2. Dim filter As Date
    3. Dim startdatum As Date = CDate("01.10.2015")
    4. For i = 0 To LogsBindingSource.Count - 1
    5. Dim logrow = DirectCast(DirectCast(LogsBindingSource.Item(i), DataRowView).Row, Daten.LogsRow)
    6. If logrow.Temp >= 175 Then
    7. datum.Add(logrow.Time)
    8. End If
    9. Next
    10. For i = 0 To datum.Count - 1
    11. Daten.Ergebnis.AddErgebnisRow(datum(i).Date, datum(i).TimeOfDay)
    12. Next
    13. For j = 0 To tage
    14. filter = startdatum.AddDays(j)
    15. ErgebnisBindingSource.Filter = "Tag = '" & filter & "'"
    16. If ErgebnisBindingSource.Count <> 0 And j <= ErgebnisBindingSource.Count - 1 Then
    17. Dim ergebnis As TimeSpan
    18. Dim first = DirectCast(DirectCast(ErgebnisBindingSource.Item(0), DataRowView).Row, Daten.ErgebnisRow)
    19. Dim last = DirectCast(DirectCast(ErgebnisBindingSource.Item(ErgebnisBindingSource.Count - 1), DataRowView).Row, Daten.ErgebnisRow)
    20. ergebnis = last.Zeit - first.Zeit
    21. Daten.Stunden.AddStundenRow(first.Tag, ergebnis)
    22. ErgebnisBindingSource.Filter = ""
    23. End If
    24. Next