Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Diese Funktion schneller machen? (https://www.delphipraxis.net/35557-diese-funktion-schneller-machen.html)

Pseudemys Nelsoni 8. Dez 2004 23:39


Diese Funktion schneller machen?
 
ok, diese funktion ist nur ein beispiel, aber viele meiner andere laufen genauso ab...

Delphi-Quellcode:
function fmtstr(const s: string; const c: char): string;
var
  i: integer;
  b: boolean;
begin
  result := ''; b := false;
  for i := 1 to length(s) do
  begin
    if s[i] = c then
    begin
      if (result = '') or (b = true) then
        continue;
      b := true;
    end
    else b := false;
    result := result + s[i];
  end;
  if (result <> '') and (result[length(result)] = c) then
    setstring(result, pchar(result), length(result)-1);
end;
ziel dieser funktion ist es einen string "ordentlich" zu machen, anhand des seperators.... also wenn ich z.b so einen string übergebe:

Zitat:

..hi.bla.....blubb....
wird die funktion:

Zitat:

hi.bla.blubb
zurückgeben.

wenn ich diese funktion 1million mal in einer schleife aufrufe dauert das ganze ca 1,094 sekunden....

gibt es irgendwie eine schnellere methode für diese funktion? es sollten keine funktionen aus der VCL verwendet werden.

jbg 8. Dez 2004 23:47

Re: Diese Funktion schneller machen?
 
Zitat:

Zitat von Pseudemys Nelsoni
result := result + s[i];

Das kostet auf Dauer sehr viel Rechenzeit, da ein neuer Speicherbereich mit einem Byte mehr reserviert wird, der alte String dort hinein kopiert und das Zeichen angehängt wird. Zusätzlich muss der alte String-Speicher freigegeben werden.
Und dieses Prozedere wird nun 1 Mio mal ausgeführt.
Besser du setzt Result vor der Schleife auf die Worst-Case Länge (in deinem Fall SetLength(Result, Length(S))). Nun kannst du die Zeichen direkt zuweisen "Inc(RealLen);Result[RealLen] := S[i];". Nach dem Schleifendurchlauf setzt du nun mit SetLength(Result, RealLen) die entgültige Länge fest.


Zitat:

Delphi-Quellcode:
  if (result <> '') and (result[length(result)] = c) then
    setstring(result, pchar(result), length(result)-1);

Hätte es nicht auch SetLength(Result, Length(Result) - 1) getan?


Für was brauchst du denn b. Das wird doch gar nicht ausgewertet.

Pseudemys Nelsoni 8. Dez 2004 23:59

Re: Diese Funktion schneller machen?
 
hallo jbg,

danke für deine antwort, ich werde versuchen es umzusetzen.

b ist true wenn das letzte zeichen der seperator war, so vermeide ich das ein seperator doppelt geschrieben wird.


EDIT:

Delphi-Quellcode:
function fmtstr(const s: string; const c: char): string;
var
  i, len: integer;
  b: boolean;
begin
  Result := '';
  if s <> '' then
  begin
    setlength(result, length(s));
    len := 0; b := false;
    for i := 1 to length(s) do
    begin
      if s[i] = c then
      begin
        if (result[1] = #0) or (b = true) then
          continue;
        b := true;
      end
      else b := false;
      len := len + 1;
      result[len] := s[i];
    end;
    if result[length(result)] = c then
      setlength(result, len-1)
    else setlength(result, len);
  end;
end;
was ist denn hier falsch?

wenn ich das tue:

Zitat:

test := fmtstr('s.u...', '.');
dann ist test "s.u."


wieso ist der punkt am ende noch da?

jbg 9. Dez 2004 07:47

Re: Diese Funktion schneller machen?
 
Zitat:

Delphi-Quellcode:
if (result[1] = #0) or (b = true) then

Das ist nicht dasselbe wie oben. Das Result[1] zeigt dir nicht an, dass der String leer ist. Das kannst du mit "len = 0" prüfen. Und ein "b = true" kann tötlich enden. Lass einfach das "=true" weg. Und bei "b=false" kann man auch schreiben "not b". Beides ist erstens kürzer und auch irgendwie besser erkennbar.

Zitat:

Delphi-Quellcode:
    if result[length(result)] = c then
      setlength(result, len-1)
    else setlength(result, len);

Das Length(Result) ist zu diesem Zeitpunkt ja nicht zwangsläufig das letzte Zeichen. Das steht nämlich in Result[len]. Und du kannst hier die zwei SetLength aufrufe zu einem machen, indem du bei dem TRUE-Code der if-Abfrage einfach Len dekrementierst. Das ist nämlich der einzige Unterschied zum anderen SetLength() Aufruf.

Pseudemys Nelsoni 9. Dez 2004 07:51

Re: Diese Funktion schneller machen?
 
moin jbg,

habe es nun so:

Delphi-Quellcode:
function fmtstr(const s: string; const c: char): string;
var
  i, len: integer;
  b: boolean;
begin
  if s <> '' then
  begin
    len := 0; b := false;
    setlength(result, length(s));
    result[1] := #0;
    for i := 1 to length(s) do
    begin
      if s[i] = c then
      begin
        if (result[1] = #0) or (b) then
        begin
          b := true;
          continue;
        end;
        b := true;
      end
      else b := false;
      len := len + 1;
      result[len] := s[i];
    end;
    if result[len] = c then
      setlength(result, len-1)
    else setlength(result, len);
  end;
end;
funktioniet einwandfrei, danke nochmal.

was meinst du mit "tödlich" enden? generell meine boolesche variable dort oder das ich "= true" benutzt habe?

btw: kann ich das doppelte "b := true" irgendwie zu einem machen?

Robert Marquardt 9. Dez 2004 08:09

Re: Diese Funktion schneller machen?
 
Ich wuerde das letzte Zeichen am Ende einmal pruefen und gegebenenfalls weghauen.
Damit verschwindet dieser unsinnige und unelegante Test mit der booleschen Variablen.

Pseudemys Nelsoni 9. Dez 2004 08:20

Re: Diese Funktion schneller machen?
 
brauche die variable aber für die mittleren seperatoren, wenn B true ist, dann war das zeichen davor bereits der seperator

Muetze1 9. Dez 2004 08:55

Re: Diese Funktion schneller machen?
 
Moin!

Ich frage mich ob es nicht schneller sein würde, mit Pos ein doppelten Separator zu suchen und wenn man was findet einfach ab da mit der Schleife weiter zu laufen und zu sehen wieviele Separatoren noch kommen. Wenn man in der Schleife einen nicht Separator findet, dann kannst du mit Delete() doch bei der Position von Pos()+1 bis zur aktuellen Stelle die Zeichen löschen und gut. Sollte das nicht schneller gehen als auch noch die Strings in der grossen Schleife durchzugehen. Und mit Pos() klappt es auch, da ein .. nachher nicht mehr zu finden sein sollte.

Nur mal so als Idee...

MfG
Muetze1

jim_raynor 9. Dez 2004 09:22

Re: Diese Funktion schneller machen?
 
Zitat:

Zitat von Muetze1
Sollte das nicht schneller gehen als auch noch die Strings in der grossen Schleife durchzugehen. Und mit Pos() klappt es auch, da ein .. nachher nicht mehr zu finden sein sollte.

Ich bezweifel das ständige Pos aufrufe schneller sind.
1. Ist ein Funktionsaufruf immer "Verhältnismäßig" langsam.
2. geht Pos immer von Anfang den String durch. Macht also viele unnütze Aktionen.
3. Bei Delete ist doch das gleiche Probleme wie viele SetLengths. Es wird jedes mal neuer Speicher angefordert und alter freigegeben. Was insgesamt sicherlich negativ auf die Performance ausschlagen wird.

Einzige Optimierung die mir noch einfallen würde ist, am Anfang alle Separatoren zu überspringen.

Delphi-Quellcode:
var
  Start: Integer;
begin
  Len:=Length(s);
Start:=1;
  while (result[Start]=c) and (Start<Len) do
    inc(Start);
for i := Start to length(s) do
(irgendwie sowas) Dadurch spart man sich das result[1] = #0 im if.

Statt Len := Len+1 benutze inc(Len);

statt immer s[i] und result[len] zu machen könntest du auch einen Pointer (PChar) verwenden, der immer erhöht wird.[/delphi]

Robert Marquardt 9. Dez 2004 09:29

Re: Diese Funktion schneller machen?
 
Wie waere es denn mit
Result := StringReplace(S, Ch + Ch, Ch, [rfReplaceAll]);
Dann muss nur noch auf ein Ch am Ende getestet werden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:18 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz