Datenaufzeichnung - z.B. maximal 100 Werte - wie die übrigen Werte "abschneiden"

  • VB.NET
  • .NET (FX) 4.5–4.8

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

    Datenaufzeichnung - z.B. maximal 100 Werte - wie die übrigen Werte "abschneiden"

    Hallo Leute,

    ich möchte nach dem Programmstart in einem Double-Array maximal 100 Werte speichern, die ich alle paar Sekunden abfrage.
    Beim Start werden die Werte in den nächsten freien Array-Index geschrieben.
    Wird nun Index 100 erreicht, dann sollen alle Werte um eins nach links rutschen (also der allererste Wert gelöscht werden).
    Es sollen also nur immer maximal die letzten 100 gemessenen Werte im Array zu finden sein.

    Wie macht man das am besten ressourcenschonend.
    Alle werte mit einer For-Nex-Schleife nach links zu rücken, finde ich etwas viel Rechenarbeit.
    Gibt es da etwas wie bei den Stringoperationen?

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Dafür gibt es die Take- und Skip-Extensions:
    Take gibt x Einträge wieder, Skip überspringt eine entsprechende Anzahl.
    Am Ende musst Du es nur wieder zu einem Array machen. Also

    VB.NET-Quellcode

    1. DeinArray = DeinArray.Skip(DeinArray.Count - 100).ToArray
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Was spricht gegen so etwas hier:
    Spoiler anzeigen

    C#-Quellcode

    1. // From: http://stackoverflow.com/a/5923604/1018144
    2. /// <summary>
    3. /// Represents a first-in, first-out collection of objects with a max capacity
    4. /// </summary>
    5. /// <typeparam name="T">Specifies the type of elements in the queue.</typeparam>
    6. public class FixedSizedQueue<T> :Queue<T>
    7. {
    8. private readonly int maxQueueSize;
    9. private readonly object syncRoot = new object();
    10. /// <summary>
    11. /// Initializes a new instance of the System.Collections.Generic.Queue`1 class that is empty and has a max capacity.
    12. /// </summary>
    13. /// <param name="maxQueueSize"></param>
    14. public FixedSizedQueue(int maxQueueSize)
    15. {
    16. this.maxQueueSize = maxQueueSize;
    17. }
    18. /// <summary>
    19. /// Adds an object to the end of the System.Collections.Generic.Queue`1.
    20. /// </summary>
    21. /// <param name="item">The object to add to the System.Collections.Generic.Queue`1. The value can be null for reference types.</param>
    22. public new void Enqueue(T item)
    23. {
    24. lock (syncRoot)
    25. {
    26. base.Enqueue(item);
    27. if (base.Count > this.maxQueueSize)
    28. {
    29. base.Dequeue();
    30. }
    31. }
    32. }
    33. }
    @slice
    Die Länge des Codes vs. 1 Zeile Code spricht dagegen ;-).
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Nimm eine Queue

    Was heist das genau? Wie sieht das aus?

    Mit ressourcenschonend meine ich hauptsächlich die Rechenpower. Speicher haben die Systeme heutzutage eh genug.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    hauptsächlich die Rechenpower

    Und allokieren von Speicher und Garbage Collection brauchen jetzt keine Rechenpower? :rolleyes:

    Um mal einen Verlgleich zu haben - wenn 1000 Elemente in das Array geschrieben werden:
    TestQueue nimmt die von @slice vorgeschlagene Klasse.
    TestArrayCopyArray verwendet die Funktion Array.Copy von @JRole
    TestArraySkipToArray halt die Linq-Funktionen

    Brainfuck-Quellcode

    1. | Method | Size | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
    2. |------------------- |----- |-------------:|-----------:|-----------:|----------:|--------:|-----------:|
    3. | TestQueue | 100 | 16.913 us | 0.2129 us | 0.1991 us | 0.1831 | - | 1232 B |
    4. | TestArrayCopyArray | 100 | 8.350 us | 0.0784 us | 0.0695 us | 0.0610 | - | 424 B |
    5. | TestArraySkipToArray | 100 | 318.706 us | 6.3308 us | 13.0743 us | 151.3672 | - | 952424 B |
    Ich sehe ein, dass es effektivere Wege als den von mir vorgeschlagenen gibt. Aber: Wenn sowas einmalig bei jedem Programmstart ausgeführt wird, dürfte die Performance praktisch wohl irrelevant sein. Wir bewegen uns im Mikrosekundenbereich, wenn ich die Werte richtig interpretiere. Da wird noch nicht mal ne Millisekunde im schlimmsten Fall überschritten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Habt Verstaendniss mit diesem Post, er dient jediglich dem Austausch in dem vom TE im Kontext stehender Anfrage.

    Neben der Queue-klasse gibt es auch noch die Stack-klasse. Von der Theorie(und Praxis wenn man seine Bibel beiseitelegt) her kann man mit beiden Klassen gleiche Resultate erzielen, in der Praxis wird der Stack in einem Mikrocontroller auch auf Hardwareebene verwendet.
    Stack arbeitet nach dem LIFO Prinzip, Queue nach dem FIFO Prinzip.

    Wie erwaehnt gibt es unterschiedliche Methoden um am Ziel anzukommen... außerdem kann man Typensicher mit den Klassen arbeiten.

    VB.NET-Quellcode

    1. Option Strict On
    2. Module module1
    3. Sub Main()
    4. Dim DecimalStack As New Stack(Of Decimal)
    5. DecimalStack.Push(7)
    6. DecimalStack.Push(11)
    7. DecimalStack.Push(13)
    8. 'Holt den ersten Push vom Stack (Dec 7)
    9. Console.WriteLine(DecimalStack.Pop.ToString)
    10. 'Holt den letzt Push vom Stack (Dec 13)
    11. Console.WriteLine(DecimalStack.Last.ToString)
    12. End Sub
    13. End Module

    JRole schrieb:

    @Haudruferzappeltnoch Ja, tut es.

    Was? Nein? Hast du überhaupt mal da rein geschaut? Das Array wird nur kopiert, wenn die Größe zu klein ist. Sonst ist es ein ganz normaler Ring-Buffer, wo der Pointer im Kreis rundläuft. Nimmst du die Items wieder raus, wird hier nichts verschoben. Oder was meinst du?


    ATXMega256@32MHz schrieb:

    Von der Theorie(und Praxis wenn man seine Bibel beiseitelegt) her kann man mit beiden Klassen gleiche Resultate erzielen

    Was? Wie das denn? Dein Beispiel ist schon falsch, die Reihenfolge ist eine andere (13, 7), so wie man es beim Stack erwartet. Und du kannst mit Last zwar auf den ersten hinzugefügten Eintrag kommen, aber diese nicht rausnehmen und damit den gewollten Fall gar nicht abbilden?
    Ja, aber darum ging es doch gar nicht? Haudruferzappeltnoch hat ja geschrieben dann wird dort auch sicher ein Array kopiert werden. Es ging um das ständige kopieren des ganzen Speichers, was sehr ungeschickt ist. Bei der Linq variante wird alles immer in ein neues Array geschrieben:


    CopyArray verschiebt alles:


    Die Queue verschiebt aber nicht immer alles. Die verschiebt einfach den Anfang des Arrays immer um 1 nach vorne, wenn ein neues Element rein kommt und fängt vorne wieder an, wenn sie hinten angekommen ist. Das Array wird also einfach als Ring gesehen mit verschiebbarem Anfang:
    Vielen Dank für Eure Zahlreichen Antworten.
    Ich habe die Lösung von @VaporiZed gewählt.
    Bilder
    • 05072023100857.jpg

      73,41 kB, 527×374, 213 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    So bildhaft dargestellt wirkt es ja erstmal einleuchtend, aber der Speicher hat ja Speicherplätze und da gibt es gewiss keine Sondergurken die im Kreis hintereinander gereiht sind.
    Wenn ein Array erstmal adressiert ist, dann hat man da eine bestimmte Menge an Plätzen reserviert. Aber egal wieviel man reserviert irgendwann ist halt immer zu Ende.
    Deswegen sei dazu gesagt der eigentliche Trick bei so einem "Ring"-Array ist die dynamische Berechnung des Indexes mit einem Modulus.
    Das Prinzip hatte ich aber gar nicht mehr auf dem Schirm.