Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Zeile aus Stringlist löschen, wie optimieren? (https://www.delphipraxis.net/179098-zeile-aus-stringlist-loeschen-wie-optimieren.html)

Popov 14. Feb 2014 13:36

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Also löschen dauert wirklich lange, kopieren fast nichts. Ich hab ein Beispiel erstellt mit etwa 1 Mio Daten, davon 10% Leerzeilen. Erstellung etwa 150 ms, Löschung etwa 2 min, Kopiervorgang etwa 100 ms. Also statt löschen der Leerzeilen vielleicht besser kopieren der anderen Zeilen.

Hier das Beispiel mit dem ich gerechnet habe:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
const
  txt = 'qwertzuiopüasdfghjklöäyxcvbnm';
var
  sl, sl2: TStringList;
  i, t: Integer;
  t1, t2: TTime;
begin
  sl := TStringList.Create;
  sl2 := TStringList.Create;
  try
    //--- 1 Mio. Daten mit etw 10% Leerzeilen erstellen / Dauer etwa 150 ms

    t1 := Now;
    Cursor := crHourGlass;

    for i := 1 to 1000000 do
      if Random(10) = 1 then sl.Add('') else sl.Add(txt);

    Cursor := crDefault;
    t2 := Now;
    t := MilliSecondsBetween(t1, t2);
    ShowMessage(Format('Count sl: %d | Dauer der Erstellung: %d ms', [sl.Count, t]));

    //--- 10% Daten (leerzeilen) entfernen / Dauer etwa 120000 ms

    { 
    t1 := Now;
    Cursor := crHourGlass;

    for i := (sl.Count - 1) downto 0 do
      if sl[i] = '' then sl.Delete(i);

    Cursor := crDefault;
    t2 := Now;
    t := MilliSecondsBetween(t1, t2);
    ShowMessage(Format('Count sl: %d | Dauert des Löschvorgangs: %d ms', [sl.Count, t]));
    }

    //--- 90% Daten (ohne leerzeilen) kopieren / Dauer etwa 300 ms
    { }
    t1 := Now;
    Cursor := crHourGlass;

    sl2.Capacity := sl.Count;
    for i := 0 to sl.Count - 1 do //korrigiert <<<<<<<<<<<<<
      if sl[i] <> '' then sl2.Add(sl[i]);

    sl.Assign(sl2);
    sl.Capacity := sl.Count; //Korrektur nach unten

    Cursor := crDefault;
    t2 := Now;
    t := MilliSecondsBetween(t1, t2);
    ShowMessage(Format('Count sl: %d | Dauer des Kopiervorgangs: %d ms', [sl.Count, t]));

  finally
    sl2.Free;
    sl.Free;
  end;

end;
//EDIT: sorry, habe beim optimieren in letzter for Schleife downto statt to geschrieben. Die Ergebnisse bleiben aber.

//EDIT2: Apropos Speicher, Capacity sollte am Ende wieder korrigiert werden.

himitsu 14. Feb 2014 13:53

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Zitat:

Zitat von p80286 (Beitrag 1247852)
{leerzeilen löschen}
Delphi-Quellcode:
Stringliste.loadfromfile('Testdatei');
..
for i:=Stringliste.count-1 downto 0 do
  if length(Stringliste[i])=0 then Stringliste.delete(i);
Hat man mehr als 1 Mio Zeilen, kann das schon dauern. Darum meine Frage, wie kann ich das optimieren?

Ein etwas besseres Laufzeitverhalten habe ich mit
Delphi-Quellcode:
for i:=Stringliste.count-1 downto 0 do begin
  if length(Stringliste[i])>0 then stringlist2.insert(0,stringlist[i]);
  Stringlist.delete(i);
end;
(das Verhältnis ist etwa 6:5)


Als untauglich hat sich erwiesen:
Delphi-Quellcode:
p:=pos(#13#10#13#10,string);
while p>0 do begin
  delete(string,p,2);
  p:=posex(#13#10#13#10,string,p-1);
end
Da beim TStringlist.Delete letztlich nur 3 Pointer verschoben werden erhoffe ich mir von einer Pointerliste auch keine große Verbesserung.

All zuviel kann man da eh nicht optimieren.

1. es wird ein Pointer aus der Liste entfernt UND die Pointer der nachfolgenden Strings werden verschoben
2. die Referenzen der zukopierenden Strings werden kopiert, und die Referenzzählung wird angesprochen (Stringinhalte werden nicht kopiert)
3. erst wird aus allen Strings/Zeilen EIN großer String gebastelt, dann wird via StringReplace "jeder" doppelte Zeilenumbruch einzeln entfernt (Achtung, bei 3 und mehr aufeinanderfolgenden Zeilenumbrüchen wird nur jeder Zweite entfernt), dabei werden alle nachfolgenden Zeichen jedesmal umkopiert, und dann wird der ganze String wieder in viele Einzelstrings zerlegt

Auslesen als TEXT geht nur bei einem Memo (TMemoStrings) schneller, da dort der Text zusammenhängend im RAM liegt. (aber das Löschen der Leerzeilen sollte auch da temporärn einer TStringList erfolgen, da das TMemo arschlangsam ist).




Wie kommen die Daten denn in die TStringList?
Was am Schnellsten ginge, wäre die Leerstrings garnicht erst aufzunehmen.
Also die Add-Methode überschreiben und bei dem ungewollten Leerstring abbrechen.

p80286 14. Feb 2014 14:24

AW: Zeile aus Stringlist löschen, wie optimieren?
 
So chefe stört nicht mehr...
erst einmal vielen Dank für die vielen Rückmeldungen.

Zunächst, alle Zeilen müssen vorliegen und erst dann entscheidet sich welche Zeilen gelöscht werden. Sehr oft sind Leerzeilen betroffen und dafür hab ich dann eine Spezialbehandlung.
Die Lösung "nicht einlesen" entfällt daher.

Die Prüfung auf
Delphi-Quellcode:
Stringlist[i]=''
hab ich ausprobiert und gefühlt sind da ein paar Sekunden herum gekommen.

Die "Kopierlösung" ist auch auf andere Zeileninhalte anwendbar, zusammen mit dem "Auftrennen" scheint das interessant zu werden. Muß ich mal testen. Das wichtigste Problem was ich sehe ist hirbei der Speicherplatzbedarf.
Mal ausprobieren.

noch mal vielen Dank
K-H

P.S. z.Zt. arbeite ich mit ca 2,5 Mio Zeilen das fluppt so oder so

Mokus 14. Feb 2014 14:35

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Zitat:

Das wichtigste Problem was ich sehe ist hirbei der Speicherplatzbedarf.
WTF ?

wenn das dein Grö´tes Problem solltest du dir alg. Gedanken machen, ob man da nicht was anders Lösen könnte ...

Furtbichler 14. Feb 2014 14:44

AW: Zeile aus Stringlist löschen, wie optimieren?
 
folgendes geht auch (ohne extra Liste)
Delphi-Quellcode:
Procedure RemoveEmptyLines (aList : TStringList);
Var
  i,j : Integer;

Begin
  j:=0;
  for i:=0 to aList.Length-1 do
    if aList[i]<>'' then begin
      aList[j] := aList[i];
      j := j + 1;
    end;
 
  SetLength(aList,j);
End;
(Ungetestet) Im Prinzip rennt man die Liste einmal durch und kopiert nur die nichtleeren Zeilen. Nach jedem Kopiervorgang erhöht man die Zielposition j um 1.

Braucht kaum/keinen extra Speicher :-)

Blup 14. Feb 2014 15:04

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Ah, da war jemand schneller, habs getestet, ist wirklich schnell.
Delphi-Quellcode:
    sl.BeginUpdate;
    try
      i2 := 0;
      for i := 0 to sl.Count - 1 do
      begin
        if sl[i] <> '' then
        begin
          sl[i2] := sl[i];
          Inc(i2);
        end;
      end;
      for i := sl.Count - 1 downto i2 do
        sl.Delete(i);
    finally
      sl.EndUpdate;
    end;

OlafSt 14. Feb 2014 15:07

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Und warum das ganze nicht Ultra-Oldschool ?

Delphi-Quellcode:
procedure bla;
var
  f: TEXTFILE;
  s: string;
  TSL: TStringList;
begin
  TSL:=TStringList.Create;
  AssignFile(f, 'BLA.TXT');
  Reset(f);
  while not eof(f) do
  begin
    ReadLn(f,s);
    if s <> '' then
      TSL.Add(s);
  end;
  CloseFile(f);
end;
Datei wird nur einmal komplett gelesen und der Speicherbedarf ist fürs Einlesen nahezu Null.

Uwe Raabe 14. Feb 2014 15:12

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Zitat:

Zitat von p80286 (Beitrag 1247882)
Das wichtigste Problem was ich sehe ist hirbei der Speicherplatzbedarf.

Das Problem ist kleiner als du vielleicht denkst. Wenn du den Inhalt einer Stringlist kopierts, werden nur die Pointer auf die Strings kopiert und nicht die Stringinhalte. Somit verbraucht die kopierte StringList kaum mehr als <Anzahl Zeilen>*<Sizeof(Pointer)> an zusätzlichem Speicher.

p80286 14. Feb 2014 15:33

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1247890)
Das Problem ist kleiner als du vielleicht denkst. Wenn du den Inhalt einer Stringlist kopierts, werden nur die Pointer auf die Strings kopiert und nicht die Stringinhalte. Somit verbraucht die kopierte StringList kaum mehr als <Anzahl Zeilen>*<Sizeof(Pointer)> an zusätzlichem Speicher.

Das ist ein Wort!
ich war mir nicht sicher ob nicht vielleicht doch die Inhalte kopiert werden!

Gruß
K-H

Neutral General 14. Feb 2014 16:28

AW: Zeile aus Stringlist löschen, wie optimieren?
 
Wie siehts mit StringReplace aus? Schonmal probiert wie das abschneidet?

Delphi-Quellcode:
StringReplace(Stringlist.Text,#13#10,'',[rfReplaceAll])


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:03 Uhr.
Seite 2 von 3     12 3      

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