![]() |
AW: Schnellstes Entfernen von Chars aus einem String?
Es gibt kein Set of Char WideChar.
Unit System.Character oder der Char-Helper. |
AW: Schnellstes Entfernen von Chars aus einem String?
Ohne mir nun den Code von Pos anzugucken - Pos kann mehr als nur ein Zeichen vergleichen, es kann ganze Zeichenketten vergleichen. Somit ist der Code vermutlich anders aufgebaut und dadurch langsammer.
Man kann sich das Pas auch sparen und direkt die Chars überprüfen. Dann muss man drauf achten, dass keiner der Strings leer ist. Hier ein Beispiel:
Delphi-Quellcode:
function RemoveCharsFromString(const AStr, CharsToRemove: string): string;
var i, k: Integer; begin Result := AStr; if Length(CharsToRemove) = 0 then Exit; for k := 0 to Length(CharsToRemove) do for i := Length(Result) downto 0 do if Length(Result) > 0 then if CharsToRemove[k] = Result[i] then Delete(Result, i, 1); end; |
AW: Schnellstes Entfernen von Chars aus einem String?
Zitat:
Weil ein Set compilerbedingt nur aus maximal 256 Elementen bestehen kann. Zitat:
|
AW: Schnellstes Entfernen von Chars aus einem String?
Zitat:
|
AW: Schnellstes Entfernen von Chars aus einem String?
![]() ![]() ![]() ... They ran a challenge for a faster StringReplace (Ansi StringReplace challenge), and the 'winner' was 14 times faster than the Delphi RTL: ![]() |
AW: Schnellstes Entfernen von Chars aus einem String?
Zitat:
Set hat max 256 Elemente. Set kann keine WideChars. Die "nur" 256 Elemente sollte bei diesem Anwendungsfall keine Rolle spielen. Keine WideChars halte ich eher für kritisch, weil die Funktion ev. nicht das macht, was der Anwender erwartet. Du kannst z.B. einem TSysCharSet mit Include(SetName,AnsiChar($221A)) ein Wurzelzeichen hinzufügen. nur ist es dann im Set eben nicht mehr das Wurzelzeichen sondern #$1A. In einem Programm wird es ev. so sein, dass der Anwender die zu entfernenden Zeichen in ein Edit eingibt. Die Zeichen werden dann in ein Set übertragen. Und der Anwender fragt sich dann was er falsch macht, wenn das Ergebnis nicht seinen Erwartungen entspricht. |
AW: Schnellstes Entfernen von Chars aus einem String?
Habe mal meine Funktion entsprechend angepasst:
Delphi-Quellcode:
Ist sogar interessanterweise schneller als mein Ursprünglicher Code mit dem Set. Amateurprofis Funktion hat ähnliche Performance.
function RemoveCharsFromString(const AStr, CharsToRemove: String): string;
var I, J: Integer; L: array[Char] of Boolean; begin FillChar(L, SizeOf(L), #0); for I := 1 to Length(CharsToRemove) do begin L[CharsToRemove[I]] := true; end; SetLength(Result, Length(AStr)); J := 1; for I := 1 to Length(AStr) do begin if (not L[AStr[I]]) then begin Result[J] := AStr[I]; J := J + 1; end; end; SetLength(Result, J - 1); end;
Code:
Zacherl (set): 641
Zacherl (lookup): 438 Amateurprofi: 500 |
AW: Schnellstes Entfernen von Chars aus einem String?
Zitat:
Delphi-Quellcode:
ist keine gute Idee, da bei jedem zu löschenden Zeichen alle nachfolgenden Elemente umkopiert werden müssen, was im Average und Worst Case zu quadratischer Laufzeit führt.
Delete
Ich würde folgendes vorschlagen:
Delphi-Quellcode:
Das ist für mich der beste Kompromiss aus Geschwindigkeit, Funktionalität und Einfachheit. Wenn man will, kann man das Pos natürlich auch noch durch eine eigene Schleife ersetzen.
function RemoveCharsFromString(const AStr, CharsToRemove: string): string;
var i, NewLength: Integer; begin SetLength(Result, AStr); NewLength := 0; for i := 1 to Length(AStr) do begin if Pos(CharsToRemove, AStr[i]) = 0 then begin Result[NewLength] := AStr[i]; inc(NewLength); end; end; SetLength(Result, NewLength); end; Wenn man unbedingt noch mehr rausholen will: Zu Sets bzw. Array of Bool[Char] ist zu sagen, dass es wohl schon einen Sinn haben dürfte, weshalb Set auf 256 Elemente begrenzt ist. Mit jedem weiteren Element wächst auch der Speicherverbrauch. Bei WideChar belegt
Delphi-Quellcode:
bereits 65 Kilobyte. Würde man statt Bools einzelne Bits verwenden wie bei
Array of Bool
Delphi-Quellcode:
, sind es immer noch 8 Kilobyte. Das ist zu groß um komplett in den CPU-Cache geladen zu werden. Würde man sequenziell durch den Bereich durchlaufen, wäre das zwar kein Problem, aber Sets sind prinzipbedingt Random Access. Würde mich nicht wundern, wenn es schneller wäre, einfach in einer Schleife durch die zu löschenden Elemente zu gehen und immer zu vergleichen (wie in meinem Code), solange es eine überschaubare Anzahl Zeichen ist, die entfernt werden soll.
Set
Für allerhöchste Performance würde ich eine Hashmap empfehlen ( ![]() |
AW: Schnellstes Entfernen von Chars aus einem String?
Zitat:
Hast du denn einmal die von dir vorgeschlagene Funktion laufen lassen? Wenn "JA", dann hättest du merken müssen 1) In der ersten Zeile
Delphi-Quellcode:
sollte eine Fehlermeldung kommen, dass man der Länge eines Strings keinen String zuweisen kann.
SetLength(Result, AStr);
2) Bei
Delphi-Quellcode:
sollte dir aufgefallen sein, dass du die Position eines Strings innerhalb eines Chars abfragst, was natürlich immer 0 ergibt.
if Pos(CharsToRemove, AStr[i]) = 0 then
3) Bei
Delphi-Quellcode:
sollte es scheppern, weil du Result[0] ein Char zuweisen willst.
Result[NewLength] := AStr[i];
inc(NewLength); Zu Zitat:
Zitat:
Sorry, falls du dich angegriffen fühlen solltest; aber wenn jemand einen Code der gleich 3 so offensichtliche Fehler enthält und so nicht einmal kompilierbar ist, als "Besten Kompromiss" vorstellt, dann juckt es mich schon in den Fingern. Ich habe, nachdem ich die Fehler in deinem Code korrigiert habe, beide Funktionen laufen lassen, deine aus #28 und meine aus #19. Als String, aus dem Zeichen entfernt werden sollen, habe ich den letzten Absatz deines Beitrages #28 und als String mit zu entfernenden Zeichen deinen Nick "Namenloser" benutzt. Die Ergebnisse waren für mich nicht überraschend. So habe ich getestet;
Delphi-Quellcode:
PROCEDURE TMain.Test;
FUNCTION TimeStamp:Int64; asm rdtsc {$IFDEF CPUX64} shl rdx,32 or rax,rdx {$ENDIF} end; const S='Zu Sets bzw. Array of Bool[Char] ist zu sagen, dass es wohl schon einen '+ 'Sinn haben dürfte, weshalb Set auf 256 Elemente begrenzt ist. Mit jedem '+ 'weiteren Element wächst auch der Speicherverbrauch. Bei WideChar belegt '+ 'Array of Bool bereits 65 Kilobyte. Würde man statt Bools einzelne Bits '+ 'verwenden wie bei Set , sind es immer noch 8 Kilobyte. Das ist zu groß '+ 'um komplett in den CPU-Cache geladen zu werden. Würde man sequenziell '+ 'durch den Bereich durchlaufen, wäre das zwar kein Problem, aber Sets '+ 'sind prinzipbedingt Random Access. Würde mich nicht wundern, wenn es '+ 'schneller wäre, einfach in einer Schleife durch die zu löschenden '+ 'Elemente zu gehen und immer zu vergleichen (wie in meinem Code), solange '+ 'es eine überschaubare Anzahl Zeichen ist, die entfernt werden soll.'; R='Namenloser'; Res:Array[Boolean] of String=('Ergebnisse verschieden','Ergebnisse gleich'); var T0,T1,T2:Int64; S1,S2:String; begin T0:=TimeStamp; S1:=RemoveCharsFromString(S,R); T1:=TimeStamp; S2:=RemoveChars(S,R); T2:=TimeStamp; Dec(T2,T1); Dec(T1,T0); ShowMessage(Res[S1=S2]+#13+IntToStr(T1)+#13+IntToStr(T2)); end; |
AW: Schnellstes Entfernen von Chars aus einem String?
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat:
Ich habe es schon etliche Male hier erlebt, dass jemand die Frage stellt „Wie mache ich am schnellsten X?“ und damit einen Optimierungswettbewerb über mehrere Seiten entfacht. Zwei Tage und zehn Seiten später kommt der Threadersteller wieder vorbei und sagt „Danke für eure Mühe, aber ich verwende nun die Lösung aus Beitrag #2, die ist für mich schnell genug“ ;) Zitat:
EDIT: Okay, ich habe jetzt zum Testen mal schnell FreePascal installiert. Testprogramm im Anhang. Hier sind die Ergebnisse:
Code:
Meine ist also nicht nur einfacher, sondern auch durchweg schneller. (CPU i7 4790K, 64 Bit)
[dev]$ ./test
Ergebnisse gleich 38388 55680 [dev]$ ./test Ergebnisse gleich 44436 54428 [dev]$ ./test Ergebnisse gleich 40326 45034 [dev]$ ./test Ergebnisse gleich 38809 48323 Was sagst du nun? Wenn ich String durch WideString ersetze und Char durch WideChar, ist es sogar noch ein bisschen krasser:
Code:
[dev]$ ./test
Ergebnisse gleich 43000 74935 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:38 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