Einzelnen Beitrag anzeigen

David Martens

Registriert seit: 29. Sep 2003
205 Beiträge
 
Delphi XE Enterprise
 
#37

Re: TStringlist mit 60000 Einträgen zu langsam

  Alt 12. Feb 2010, 00:11
Hallo,
jetzt geb ich auch mal meinen Senf dazu.
Das was hier die meiste Zeit braucht sind doch die vielen gibmir... Aufrufe.

Hier wie ich es machen würde:
Delphi-Quellcode:
    begin
      quelle := tstringlist.create;
      ziel := tstringlist.create;
      eineZeile := tstringlist.create;
      try
        //Previewdatei laden
        quelle.LoadFromFile(extractfilepath(application.exename) + 'preview2.dat');

        eineZeile.Delimiter := #9;
        eineZeile.QuoteChar := '"'; // hier bin ich mir nicht sicher ob das reicht um die stringreplace überflüssig zu machen

        for i := 0 to quelle.Count - 1 do
        begin
          // vorsichtshalber säubern, muß aber nicht sein
          eineZeile.Clear;
          // nur 1 mal parsen (und das von Delphi selbst) statt x mal immerwieder
          // hier kann wahlweise auch mit readln gearbeitet werden wenn man will
          eineZeile.DelimitedText := quelle.Strings[i];

          //Token zusammennehmen
          if pos('#' + eineZeile[1] + '#', tok) <> 0 then
            ziel.text:= ziel.text + eineZeile[0];

          //Lemma zusammennehmen
          if pos('#' + eineZeile[1] + '#', lem) <> 0 then
            begin
              schon := 0;

              if eineZeile[2] in ['<UNKNOWN>', '@card@', 'CARD', '@ord@'] then
              begin
                if (eineZeile[2] = '<UNKNOWN>') then
                begin
                  if checkbox2.checked then
                  begin
                    ziel.text := ziel.text + eineZeile[0];
                    schon := 1;
                  end;
                end
                else // alle anderen
                begin
                  if checkbox4.checked then
                  begin
                    ziel.text := ziel.text + eineZeile[0];
                    schon := 1;
                  end;
                end;
              end;

              if schon = 0 then
                ziel.text := ziel.text + eineZeile[2];
            end;

          if pos('#' + eineZeile[1] + '#', poss) <> 0 then
            ziel.Text := ziel.text + eineZeile[1];
         end;

        for i := 0 to ziel.Count - 1 do
          zielende := zielende + ' ' + ziel.Strings[i];

        memo2.text := zielende;

      finally
        quelle.Free;
        ziel.Free;
        eineZeile.Free;
      end;
Damit wird nur 1 mal geparst und dann auf die Teile direkt zugegriffen.
Ob das jetzt 100 pro funktioniert kann ich aber nicht so aus dem Hut sagen.

Um zur Diskusion beizutragen: soweit ich mich erinnern kann nutzt LoadFromFile u.Ä. die Windows API für das eigentliche Ansprechen der Datei, während readln eine Delphi (besser Pascal) eigene Umsetzung der gleichen Funktion ist. An dieser Stelle lässt sich darüber streiten, ob die Windows eigene oder die Borland/CodeGear/Embarcadero umsetzung der selben schneller ist. Ich bin ja (auch wenn ich das sonst nicht so sehe) eher für MS, alleine durch die Tatsache das MS die Funktionen auf die jeweilige Windows Version anpassen kann und Delphi von der Plattform wo das Programm dann läuft zur Compiletime keine Ahnung haben kann.

Bis Dann, und hoffentlich konnte ich helfen,
David

Nachtrag: Ich hab nochmal zusammegerechnet, du zerpflückst jede Zeile 5 mal, da hast du dein Performanceproblem. Wenn es so wie in meinem Code nicht geht kannst du auch eine Funktion schreiben die alle 3 Teile auf einmal zurückgibt und dann im "Hauptprogramm" in 3 einzelne Variablen speichert. So in etwa:
Delphi-Quellcode:
procedure aufteilen(const s : string; const sep : char; var Token, wortart, Lemma : string);
var
  t: Tstringlist;
begin
  //hier muss jetzt das zweite Wort rausgefiltert werden
  t:= tstringlist.create;
  try
    extractstrings([char(sep)], [' '], pchar(s), t);
    Token := t.Strings[0];
    wortart := t.Strings[1];
    Lemma := t.Strings[2];
  finally
    t.free;
  end;
end;

// so wirds dann benutzt, einmal am Anfang
aufteilen(quelle.strings[ii], #9, token_Variable, wortarttemp, lemmareal);
  Mit Zitat antworten Zitat