Einfügen / Ändernd von Arrayindexen

shrimps

Level-1
Beiträge
422
Reaktionspunkte
49
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,
habe da wieder etwas im Kopf ausgegraben:
Ich habe ein Array mit z.Bsp. Int-Werten.
Es hat die Größe von Bsp.: MyArray : array [1..10] of INT;

Nun folgende Idee:
Ich benötige manchmal einen "Insert" innerhalb der Reihenfolge und manchmal einen "Delete" in der Reihe.
Ich würde dann gerne ohne mühsam in einer Schleife alles weiterzuschieben bzw. zusammenzuschieben gerne
irgendwas mit Adressen und Pointern machen...

Genaueres Beispiel:
Myarr[1] = 5
Myarr[2] = 3
Myarr[3] = 2
Myarr[4] = 7

Nun möchte ich einen "Del" der [2] machen:
Danach also fogendes erhalten:
[1] = 5
[2] = 2
[3] = 7
Die "freiwerdenden" erhalten Default, bsp: 0
Bei einem Insert halt alle einen "Rauf" und der "obere" fliegt raus...
(Wobei der "Insert" halt wisen muss ab wo "verschoben" werden soll)
Geht das nicht irgendwie mit Memcopy und / Oder Pointern und Bitschiebeoperationen ?

Wie immer: Codesys V2.11

Besten Dank fürs mitgrübeln.

LG
Shrimps
 
Hallo,
da wirst du wohl nicht um vor- bzw. zurückschieben herum kommen.
Befehle wie MemCopy oder BlockMove mögen es nicht, wenn dich der Quell- und der Zielbereich überlappen - was bei dir ja der Fall ist.
Eine Andere Alternative wäre, wenn du zusätzlich noch ein Bit-Array (z.B.) in gleicher Größe und hier mit einem TRUE festlegst, welche Einträge aus dem Daten-Array verwendet werden dürfen.
Oder ... wenn du z.B. nur positive Zahlen in deinem Daten-Array hast dann setz den Index-Wert der nicht zu verwendenden Speicherstelle auf -1. Auch damit signalisierst du dann deinem Programm, das dieser Eintrag nicht verwendet wird - bzw. noch belegt werden kann ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde eine Funktion schreiben, die diese Aufgaben übernimmt. Insert oder Delete an Position X, der Rest wird entsprechend verschoben und aufgefüllt/gelöscht. Es kann pro Vorgang immer nur ein Element gelöscht oder eingeschoben werden. Das Hauptwerk vollbringt dann eine Schleife (wenn die Array nicht zu groß sind).

Oder: Wenn es denn Memcopy sein soll und das auf sich selbst kopieren problematisch ist, könnte ich mit auch vorstellen, dass man 2 Speicherbereiche nutzt und 2 Mal memcopy ausführt, also einmal hin und ein zweites Mal zurück, dann überlappt sich das nicht mit sich selbst. Die Sonderbehandlung der eingefügten Zeile (Wert X übergeben) oder der letzten Zeile bei Delete (Wert 0 übergeben) ist dann aber trotzdem noch nötig.
 
Hi Shrimps,

guck mal in die OSCAT-Basic-Bibliothek: http://www.oscat.de
Im Handbuch sind ab Kapitel 26 Listen-Funktionen beschrieben.
Die Liste wird als String gespeichert und verarbeitet. Die Elemente sind mit Trennzeichen getrennt.
Vielleicht helfen Dir diese fertigen Funktionen weiter.

Gruß
JS
 
Hallo zusammen,
erstmal besten Dank für die Ideen !

Oscat habe ich mir angesehen und zum Speichern von Integern (in meinem Fall) macht Stringverarbeitung keinen Sinn, da extrem Resourcen verbraten werden.
Zumindest war dies bei PC-Sprachen wenn ich ständig str_to_int und zurück wandele...
Dann noch das Concat etc...

Daher habe ich mich mal an die andere Idee mit den zwei Speichbereichen und den mehrfachen memcopy´s gemacht.
Z. Zt. schreibe ich einen kleinen fb welcher mit das ganze erledigt.
Gerne setze ich ihn mal hier rein, wenn er durchgetestet ist.
Die ersten Versuche mit dem memcpy waren schon ganz flott...
Nachteil meiner Umsetzung wird der Speicherverbrauch sein, aber heutzutage :cool:


Bis bald
Shrimps
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du kannst dir auch selber aus einer Array-Struktur (ohne Zeiger) eine einfach oder doppelt verkettete Liste programmieren. Man muss aber genau hinschauen welche Operationen auf dem Array/Liste bei dir überwiegen, dass die Operationen (lesen/einfügen/löschen) auf einer Liste schneller sind als auf ein Array. Ein Mehr an Speicherbedarf hast du auf jeden Fall.

Den Anwendungsfall für diese String-Listen aus Oscat habe ich bisher noch nicht gefunden. Ich glaube das ist eher was für CSV-Dateien und nichts für eine Liste als Datenstruktur.
 
Hallo nochmals,
ich habe meine Idee mit dem "Arrayschieber" gemäß einiger Ideen hier mit der Memory-Copy gelösst.
Läuft recht flott...
Ich schiebe den Code mal komplett hier rein und ggf. hat der eine oder andere ja noch ein paar Optimierungsideen ?
Ich kommentiere meine Sourcen möglichst umfangreich, aber beim Cut & n Paste hierhin wird es wegen der Schriftart und dem Twincateditor leider auseinandergerissen...
Das passiert leider auch, wenn ich die Dokumentationsfunktion im Twincat nutze und als PDF ausgebe...
Nur im Editor ist alles schon eingerückt / Tabuliert.

Hier nun der Code
LG
Shrimps
Code:
PROGRAM MAIN
VAR
    Schritt : INT;
    fbData    : _fbData;
    Index    : USINT;
    tmp         : INT;
    fbZufall    : DRAND;
END_VAR
CASE Schritt OF
0:;
    FOR Index := 1 TO 10 DO
        fbZufall(seed := Tmp);
        tmp := LREAL_TO_INT(fbZufall.Num * 100);
        fbData(Code := 1, Value := tmp, Index := Index);
    END_FOR
    Schritt := 10;

10:;
    (* Test DEL *)
    fbData(code := 3,  Value := tmp, Index := 1);
    Schritt := 20;

20:;
    (* Test INS *)
    tmp := 99;
    fbData(code := 2,  Value := tmp, Index := 1);
    Schritt := 30;

30:;

END_CASE

FUNCTION_BLOCK _fbData
VAR_INPUT
    Index        : UINT;        (* Der gewünschte Index *)
    Code        : BYTE (0..3) ;    (* 0 = Lesen, 1 = Schreiben, 2 = INS, 3 = DEL*)
END_VAR
VAR_IN_OUT
    Value        : INT;        (* Der Eingabe oder Ausgabewert, je nach Wunsch *)
END_VAR
VAR_OUTPUT
    n            : UINT;        (* Wieviel Elemente sind aktuell drin *)
    OldValue    : INT;        (* Luxus: Der Wert des letzten gelöschen Elementes *)
END_VAR
VAR CONSTANT
    MaxArray : USINT    := 10;    (* Hier wird der Speicher verschwendet *)
END_VAR
VAR
    daten    : ARRAY [1..MaxArray] OF INT ;    (* Unsere Datengrube *)
    memory    : ARRAY [1..MaxArray] OF INT;    (* Das Paralleluniversum *)
    nSize    : BYTE;                        (* Die Größe der Type in Bytes *)
    dest    , src : UDINT;                        (* Ziel und Quelladressen für das Kopieren *)
    nBytes    : UDINT;                        (* Wieviele Bytes dürfen es werden *)
    bInit         : BOOL    := TRUE;                (* Kleiner Init des FB *)
END_VAR

IF bInit THEN                    (* Luxus, falls mal eine andere Type benutzt wird *)
    nSize := SIZEOF(Value);    (* Wieviel Bytes ist die Var gross ? *)
    bInit := FALSE;            (* Init abgeschlossen *)
END_IF

IF  Index > 0 AND Index <= MaxArray THEN

CASE Code OF

0:    (* Es soll ein Wert vom Index gelesen werden *)
    Value := daten[Index];

1:    (* Es soll ein Wert in den Index geschrieben werden *)
    daten[Index] := Value;
    n := n +1 * BOOL_TO_INT(n < MaxArray);        (* Den Zähler raufzählen *)


2:    (* Es ist ein INS auf ein Index gewünscht, die Reihe muss also schrumpfen *)
    OldValue := daten[MaxArray];                (* Wir merken uns den alten Wert, falls es jemand später braucht. *)
    MEMSET(ADR(memory), 0, nSize * MaxArray);    (* Wir löschen unser memory *)

    IF Index = 1 THEN                            (* Bei 1 ist immer alles anders *)
        dest := ADR(memory[2]);                (*  Das Ziel ist daher die 2 *)
        src    := ADR(daten[1]);                    (* Die Quelle muss 1 sein *)
        nBytes    := nSize * MaxArray -1;            (* Wir müssen Anzahl -1 Daten schaufeln *)
    ELSE
        dest := ADR(memory[1]);                (* Es ist ein Eintrag > 1 gewünscht, daher *)
        src    := ADR(daten[1]);                    (* Müssen wir den unteren Teil *)
        nBytes    := nSize * (Index -1);            (* bis vor der Position retten und *)
        MEMCPY(dest,src,nBytes);                (* Nun den vorderen Teil kopieren *)

        dest := ADR(memory[Index+1]);            (* Jetzt den hinteren Teil *)
        src    := ADR(daten[Index]);                (* Adressieren und *)
        nBytes    := nSize * (MaxArray - Index +1);    (* Die Menge berechnen *)
    END_IF

        MEMCPY(dest,src,nBytes);                (* Wir schaufeln den hinteren Teil rüber *)

        dest := ADR(daten[1]);                    (* Fertig, nun alles *)
        src    := ADR(memory[1]);                (* Für das Rücksichern *)
        nBytes    := SIZEOF(daten);                (* Aller Daten, das dürfte schneller sein *)
        MEMCPY(dest,src,nBytes);                (* Nun alles in die Originaldaten schaufeln *)

        n := n +1 * BOOL_TO_INT(n < MaxArray);    (* Den Zähler runterzählen *)
        daten[Index] := Value;                    (* Hier nun endlich den gewünschten Wert eintragen *)


3:    (* Es ist ein DEL auf ein Index gewünscht, die Reihe muss also schrumpfen *)
    OldValue := daten[Index];                    (* Wir merken uns den alten Wert, falls es jemand später braucht. *)
    MEMSET(ADR(memory), 0, nSize * MaxArray);    (* Wir löschen unser memory *)
    IF Index = 1 THEN                            (* Wenn der erste ! Eintrag gelöscht werden soll, dann: *)
        dest := ADR(memory[1]);                (* Ist das Ziel die 1 und *)
        src    := ADR(daten[2]);                    (* Die Quelle die 2 !!! *)
        nBytes    := nSize * MaxArray -1;            (* Wir müssen Anzahl -1 Daten schaufeln *)
    ELSE
        dest := ADR(memory[1]);                (* Es ist ein Eintrag > 1 gewünscht, daher *)
        src    := ADR(daten[1]);                    (* Müssen wir den unteren Teil *)
        nBytes    := nSize * (Index -1);            (* Bis vor der Position retten und *)
        MEMCPY(dest,src,nBytes);                (* Nun den vorderen Teil kopieren *)
        dest := ADR(memory[Index]);            (* Jetzt den hinteren Teil *)
        src    := ADR(daten[Index+1]);            (* Adressieren und *)
        nBytes    := nSize * (MaxArray - Index );    (* Die Menge berechnen *)
    END_IF

    MEMCPY(dest,src,nBytes);                    (* Wir schaufeln den hinteren Teil rüber *)
    dest := ADR(daten[1]);                        (* Fertig, nun alles *)
    src    := ADR(memory[1]);                    (* Für das Rücksichern *)
    nBytes    := SIZEOF(daten);                    (* Aller Daten, das dürfte schneller sein *)

    MEMCPY(dest,src,nBytes);                    (* Nun alles in die Originaldaten schaufeln *)
    n := n -1 * BOOL_TO_INT(n > 0);                (* Den Zähler runterzählen *)
END_CASE

ELSE
    Value := -999;                                (* Wenn der Index Müll war bekommt er halt Müll *)
END_IF
 
Ohne den Code jetzt ganz ausführlich durchgesehen zu haben, würde ich noch vorschlagen ein Startbit als Input zu verwenden, aus dem dann im FB eine Flanke zum Starten der Aktion erzeugt wird. So wie der Baustein im Moment aufgebaut ist, muß man selbst dafür sogen, dass er nur einen Zyklus lang aufgerufen wird, damit nicht in jedem Zyklus eine Aktien ausgeführt wird. Du machst das in der Case-Anweisung in FB-Main. Aber das ist ein wenig eine Frage des eigenen Programmierstils.
 
Zurück
Oben