![]() |
Delphi-Version: 10.3 Rio
Array Inhalt versetzen?
Hallo,
ich habe ein "a:TArray<String>". Gibt's da vielleicht irgendein Befehl, um den Inhalt nach links und rechts zu versetzen? Beispiel: a[0]:='Auto'; a[1]:='Fahrrad'; a[2]:='Flugzeug'; Ich möchte z.B. mit einer Prozedur "nachlinks(a)" oder "nachrechts(a)" erreichen, dass der Inhalt entsprechend neu gesetzt wird. Um ein Beispiel für "nachlinks(a)" zu geben. 1. Aufruf: a[0]:='Fahrrad'; a[1]:='Flugzeug'; a[2]:='Auto'; Nächster Aufruf: a[0]:='Flugzeug'; a[1]:='Auto'; a[2]:='Fahrrad'; Ich denke, so ist es verständlich, was ich meine. Das Array hat eine unterschiedliche Größe. Mal mehr Inhalt, mal weniger. Könnte mir vorstellen, dass es hierzu was spezielles für's Array gibt, ums einfach zu lösen. Gruß Micha |
AW: Array Inhalt versetzen?
Vielleicht so?
Delphi-Quellcode:
procedure Swap(var arr: array of string; A, B: Integer);
var Tmp: string; begin Tmp := Integer(arr[A]); arr[A]) := arr[B]; arr[B]) := Tmp; end; Swap(a, 0, 1); |
AW: Array Inhalt versetzen?
Dafür wäre eine TList<> deutlich besser geeignet:
Delphi-Quellcode:
Ergbenis:
var
a: TList<String>; // in diesem besonderen Fall gäbe es sogar TStringlist als eigenen Typen begin a[0]:='Auto'; a[1]:='Fahrrad'; a[2]:='Flugzeug'; a.Insert(0, a.Extract(2)); end; a[0]='Flugzeug'; a[1]='Auto'; a[2]='Fahrrad'; |
AW: Array Inhalt versetzen?
Zitat:
Delphi-Quellcode:
procedure Swap(var arr: array of string; A, B: Integer);
var Tmp: string; begin Tmp := arr[A]; arr[A]) := arr[B]; arr[B]) := Tmp; end; |
AW: Array Inhalt versetzen?
Das war einfach frei getippt und von irgendwoher noch kopiert. Klar ist das komplett falsch aber der Swap ansich sollte klar sein.
Wer A zwischenspeichern, A B zuweisen, B den zwischengespeicherten Wert zuweisen. Hab auch ehrlich gesagt nicht über die Typen nachgedacht. Ist mir auch egal, denn der Sinn sollte klar sein ;) |
AW: Array Inhalt versetzen?
Zitat:
|
AW: Array Inhalt versetzen?
Zitat:
Delphi-Quellcode:
SetLength(A, 3);
A[0] := 'Auto'; A[1] := 'Fahrrad'; A[2] := 'Flugzeug'; Insert(A[2], A, 1); Delete(A, 3, 1); |
AW: Array Inhalt versetzen?
Zitat:
|
AW: Array Inhalt versetzen?
Danke für die vielen Antworten.
Ich will es noch mit meinem "TArray<String>" probieren. Trotzdem Danke @Medium für die Info TList. Ich habe jetzt "nach links verschoben" getestet und es geht:
Code:
Die andere Richtung (nach rechts) habe ich so gemacht:
Insert(A[0], A, Length(A));
Delete(A,0,1); // oder auch so: SetLength(A,Length(A)+1); A[Length(A)-1] := A[0]; Delete(A,0,1);
Code:
* Verstehe ich nicht so ganz. Davor habe ich ja ein Delete. Also ich lösche den letzten Inhalt. Aber da wird wohl die Array-Länge nicht gekürzt. Wobei das mit dem obigen Code (nach links verschieben) dann geht. Dort habe ich kein "SetLength" nach dem "Delete". Auch geht der erste Code (nach links verschieben; der erste Teil) ganz ohne SetLength. Ein Code (nach rechts) ohne "SetLength" habe ich nicht hinbekommen. Wobei ich dachte, "Delete" kürz die Array-Länge und "Insert" macht die Array-Länge automatisch größer. Scheint aber wohl damit zusammenzuhängen, wo man etwas einfügt, sprich am Anfang oder am Ende.
SetLength(A,Length(A)+1);
Insert(A[Length(A)-1], A, 0); Delete(A,Length(A)-1,1); SetLength(A,Length(A)-1); // * Jedenfalls muss ich hier mit "Length" arbeiten, da das Array ja nicht immer nur 3 Inhalte hat. Kann auch al mehr sein. Aber dann nicht hundert/tausend... vielleicht max. bis 20. Getestet habe ich es gerade mit 9 Inhalten. |
AW: Array Inhalt versetzen?
Zitat:
|
AW: Array Inhalt versetzen?
Zitat:
Wenn ich für "nach rechts verschieben" die beiden SetLength's rausmache, dann verschiebt er aber nicht richtig die Inhalte. Aber mal zur Info: Ich habe ein String "Dies,Das,Auto,Flugzeug,irgendwas" und mein Array fülle ich dann mit "a:=stringvariable.Split([','])". |
AW: Array Inhalt versetzen?
Ja, aber dort entspricht das SetLength zusammen mit dem := einem Insert.
Hier hast du Insert+Delete und die SetLength (ohne eine Zuweisung). Da man leider an dynamische Arrays (noch) keine Record-Helper hägen kann, um sich direkt solche Funktionen nachzurüsten und da es unmöglich ist bestehende Record-Helper zu erweitern, hab ich mir einen Record genommen, dort ein TArray<string> reingebaut, alles noch schön mit impliziten Casts und paar Methoden aufbemotzt und mir somit eine Art TStringList gebaut, die sich von der Speicherverwaltung wie ein Array verhält, aber solche netten Methoden wie z.B. Insert, Delete und Move enthält. :stupid: |
AW: Array Inhalt versetzen?
Zitat:
|
AW: Array Inhalt versetzen?
Zitat:
|
AW: Array Inhalt versetzen?
Die eine Richtung mit:
Code:
die nur mit "SetLength+1" und "SetLength-1" geht, habe ich geändert.
SetLength(A,Length(A)+1);
Insert(A[Length(A)-1], A, 0); Delete(A,Length(A)-1,1); SetLength(A,Length(A)-1); Nur ein:
Code:
reicht aber hier nicht. Er setzt hier den vorletzten Eintrag an den Anfang. Auf den letzten Eintrag im Array habe ich gar keinen Zugriff. Das lieg wohl am Aufbau von "Insert" (wegen "Length(A)-1").
Insert(A[Length(A)-1], A, 0);
Delete(A,Length(A)-1,1); Ich habe mir jedenfalls entsprechende Prozeduren gemacht (für beide Richtungen):
Code:
So geht's dann komplett ohne "SetLength".
Procedure TabToLeft(Var A:TArray<String>);
Begin Insert(A[0], A, Length(A)); Delete(A,0,1); End; Procedure TabToRight(Var A:TArray<String>); Var S : String; Begin S := A[Length(A)-1]; Insert(S, Splitted, 0); Delete(A,Length(A)-1,1); End; Danke für die Hilfe meiner Problemlösung. Gruß Micha |
AW: Array Inhalt versetzen?
Ohh, eigentlich sollte der Wert vorher kopiert und als Parameter übergeben werden,
aber könnte wirklich sein, dass hier die Compilermagic und Codeoptimierung durchschlägt, da Insert und Delete nicht wirklich so richtige "normale" Prozeduren sind. :shock: Über die Record-Operatoren hast hier dann mehr Glück, weil die komplett extrem unoptimierbar sind. Nja, direkt ist es so eigentlich auch nicht optimal, denn hier wird ja zwei mal die Länge des Arrays geändert und im extremfall auch alles bis zu zwei Mal komplett umkopiert. |
AW: Array Inhalt versetzen?
Anstatt der Änderung der Array-Länge und des damit verbundenen (internen) Umkopierens der Inhalte könntest Du relativ einfach eine Art von Ringpuffer realisieren. Hierbei würde lediglich ein Zeiger auf das Array-Element zeigen und Du könntest diesen Zeiger (Pointer) Inkrementieren bzw. Dekrementieren und den Inhalt nur im Bedarfsfall anzeigen. Allerdings weiß ich nicht, ob eine solche Lösung zu Deiner Anwendung passt oder nicht.
Gruß, Andreas |
AW: Array Inhalt versetzen?
Noch einfacher wäre ein gleichlanges Integer-Array, in welchem die Elemente auf die gewünschte Position des String-Arrays zeigen. Damit kannst Du die Reihenfolge durch Änderung der "Integer-Zeiger" einfach ändern und auch die String-Inhalte
Delphi-Quellcode:
anzeigen.
StringArray[IntegerArray[i]]
|
AW: Array Inhalt versetzen?
Zitat:
Ich kann auch mit folgendem Code keinen Fehler feststellen (getestet in 10.3.3):
Delphi-Quellcode:
procedure RotateRight(var A: TArray<String>);
begin Insert(A[Length(A)], A, 0); Delete(A, High(A), 1); end; procedure RotateLeft(var A: TArray<String>); begin Insert(A[0], A, Length(A)); Delete(A, 0, 1); end; |
AW: Array Inhalt versetzen?
Delphi-Quellcode:
Die Dinge ohne Move haben den Vorteil, dass man nichts falsch und kaputt machen kann. (so lange man die Indexprüfung nicht deaktiviert)
var
A: TArray<Integer>; T: Integer; i: Integer; begin // Hoch - BubbleMode for i := High(A) - 1 downto 0 do begin T := A[i]; A[i] := A[i + 1]; A[i + 1] := T; end; // Hoch - SingleMove T := A[0]; for i := High(A) - 1 downto 0 do A[i] := A[i + 1]; A[High(A)] := T; // Runter T := A[High(A)]; for i := High(A) downto 1 do A[i] := A[i - 1]; A[0] := T; // Hoch - FullMove T := A[0]; FinalizeArray(@A[0], TypeInfo(T), 1); // eigentlich FinalizeRecord, aber siehe InitializeRecord Move(A[1], A[0], High(A) * SizeOf(A)); InitializeArray(@A[High(A)], TypeInfo(T), 1); // InitializeRecord, aber das ist nicht öffentlich und geht letztendlich eh nur auf die Array-Funktion A[High(A)] := T; // ohne das Finalize und Initialize, wenn man für T "immer" eine Variable von ungemanagtem Typ verwendet, wie z.B. Integer oder ein Byte-Array, // denn bei Typen ala String, DynArray, Interface oder Variant zerschießt man sich sonst das automatische Speichermanagement, wenn man das nicht beachtet (eines von Beidem) Move(A[0], T, SizeOf(A)); Move(A[1], A[0], High(A) * SizeOf(A)); Move(T, A[High(A)], SizeOf(A)); |
AW: Array Inhalt versetzen?
Es wäre alles so einfach, wenn der TE bloß eine TList<String> oder grad TStringlist einsetzen würde. Jegliche potenzielle Konvertion zur notwedigen Form ist 100%ig einfacher und performanter als all die Workarounds, die hier so auftauchen. Warum nicht einfach die geeignete Datenstruktur? Das ist doch, was einen guten Programmierer ausmacht: Das richtige Werkzeug für den jeweiligen Einsatzzweck erkennen. :?
|
AW: Array Inhalt versetzen?
Zitat:
Ich bin mit meinem "...Right" zufrieden. Trotzdem Danke
Delphi-Quellcode:
Procedure TabToRight(Var A:TArray<String>);
Var S : String; Begin S := A[Length(A)-1]; Insert(S, Splitted, 0); Delete(A,Length(A)-1,1); End; Zitat:
Auch noch Danke an "himitsu" für seinen Code. Gruß Micha |
AW: Array Inhalt versetzen?
Zitat:
Delphi-Quellcode:
nicht existiert. :wink:
A[Length(A)]
|
AW: Array Inhalt versetzen?
Zitat:
|
AW: Array Inhalt versetzen?
Gute Frage: Copy&Paste-Error oder "es knallt nicht" weil Indexprüfung nicht aktiv.
|
AW: Array Inhalt versetzen?
Jedenfalls mit meiner "TabToRight" bin ich jetzt zufrieden. Anfangs war's ja noch alles mit "SetLength". Auch alles recht übersichtlich jetzt und für meinen Anwendungszweck supi.
|
AW: Array Inhalt versetzen?
Zitat:
Delphi-Quellcode:
zu einem falschen Ergebnis! Ursache ist das intern aufgerufene _DynArrayInsertElem. Da wird zunächst das Array verschoben, um am Anfang Platz zu schaffen. Dadurch schiebt sich das letzte Array-Element genau unter den von
Lenght(A) - 1
Delphi-Quellcode:
angegebenen Speicherbereich.
A[Length(A)]
|
AW: Array Inhalt versetzen?
Hatte nicht nachgesehn, aber würde dann das hier bestätigen.
Zitat:
|
AW: Array Inhalt versetzen?
Man könnte es jetzt so lösen und die Prüfung deaktivieren.
Delphi-Quellcode:
Aber wenn irgendwann am Verhalten von INSERT was geändert wird und es dann "richtig" funktioniert,
procedure RotateRight(var A: TArray<String>);
begin {$RANGECHECKS OFF} Insert(A[Length(A)], A, 0); Delete(A, High(A), 1); //{$RANGECHECKS ON} = Default ist OFF end; procedure RotateRight(var A: TArray<String>); begin {$UNDEF _TEMP_} {$IFOPT R+} {$DEFINE _TEMP_} {$ENDIF} {$RANGECHECKS OFF} Insert(A[Length(A)], A, 0); Delete(A, High(A), 1); {$IFDEF _TEMP_} {$RANGECHECKS ON} {$ENDIF} end; oder wenn es schon jetzt auf verschiedenen Plattformen unterschiedliche arbeitet (Win64, Android, ...), dann hast ein Problem. Effektiv verbleibt aber diese Lösung:
Delphi-Quellcode:
Test-Code:
procedure RotateRight(var A: TArray<String>);
var T: Temp; begin T := A[High(A)]; Insert(T, A, 0); Delete(A, High(A), 1); end; // oder :lol: procedure RotateRight(var A: TArray<String>); begin Insert(StrToInt(IntToStr(A[High(A)])), A, 0); // oder Insert(Min(A[High(A)], A[High(A)]), A, 0); Delete(A, High(A), 1); end;
Delphi-Quellcode:
Delete hat das Problem natürlich nicht, denn hier muß ja zuerst ausgelesen werden und dann wird damit die Länge geändert.
var
i, j: Integer; A: TArray<Byte>; B: array[0..7] of string; begin {$RANGECHECKS OFF} SetLength(A, 10); for i := 0 to High(B) do B[i] := StringOfChar('_', 12 * 2) + ' '; // move first +1 for i := 0 to High(A) do A[i] := $80 or i; Insert(A[Length(A)], A, 0); BinToHex(A[0], PChar(B[0]), Length(A)); Delete(A, High(A), 1); BinToHex(A[0], PChar(B[1]), Length(A)); // move first for i := 0 to High(A) do A[i] := $80 or i; Insert(A[High(A)], A, 0); BinToHex(A[0], PChar(B[2]), Length(A)); Delete(A, High(A), 1); BinToHex(A[0], PChar(B[3]), Length(A)); // move first none-optimize {$OPTIMIZATION OFF} for i := 0 to High(A) do A[i] := $80 or i; Insert(A[High(A)], A, 0); BinToHex(A[0], PChar(B[4]), Length(A)); Delete(A, High(A), 1); BinToHex(A[0], PChar(B[5]), Length(A)); {$OPTIMIZATION ON} // move last for i := 0 to High(A) do A[i] := $80 or i; Insert(A[0], A, Length(A)); BinToHex(A[0], PChar(B[6]), Length(A)); Delete(A, 0, 1); BinToHex(A[0], PChar(B[7]), Length(A)); for i := 0 to High(B) do for j := Length(A) downto 0 do Insert(' ', B[i], j * 2 + 3); ShowMessage( B[0] + 'first+1'#10 + B[1] + #10#10 + B[2] + 'first'#10 + B[3] + #10#10 + B[4] + 'first no'#10 + B[5] + #10#10 + B[6] + 'last'#10 + B[7]); end;
Delphi-Quellcode:
var
i: Integer; A: TArray<Byte>; B: string; begin SetLength(A, 10); for i := 0 to High(A) do A[i] := i; B := StringOfChar('_', Length(A) * 2); Delete(A, A[5], 1); BinToHex(A[0], PChar(B), Length(A)); for i := Length(A) downto 0 do Insert(' ', B, i * 2 + 3); ShowMessage(B); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:53 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz