![]() |
Wortliste erstellen: Zählroutine zu langsam
Liebe Leute,
ich hätte noch eine weitere Frage, die v.a. die Performance angeht. Ich habe rund 5000 Textdateien, die zeilenweise aus Wörtern bestehen (genauer: jede Zeile hat das Format ZuZählenderAusdruck TAB EinUninteressantesWort TAB NochEinUninteressantesWort). Ich möchte die einzelnen Wörter jeder Datei zählen und in eine Liste addiert zusammenfassen. Jede Textdatei hat im Schnitt 4000 Zeilen, macht insg. ~ 20000000 zu verarbeitende Zeilen. Den Code, den ich bisher dazu habe, braucht aber viel zu lang (~Stunde..). Hat jemand eine Idee, wie ich das optimieren könnte? Danke und viele Grüße, frieder
Delphi-Quellcode:
Procedure Clickblabla();
var TokenListeKorpus, tokenlist: tstringlist begin TokenListeKorpus:= tstringlist.create; tokenlist:= tstringlist.create; {Lade Textdatei in tokenliste..} ZaehleAlleWoerterDerListe(tokenlist {Quelldatei}, TokenListeKorpus {Gesamtliste}); {Gib die TokenListeKorpus aus, gib die Listen frei usw.} end; Procedure ZaehleAlleWoerterDerListe(const tokenliste: tstringlist; var TokenListeKorpus: tstringlist); var i: integer; token: string; begin for i:= 0 to tokenliste.count-1 do begin token:= gibmirtoken(tokenliste.strings[i], #9); if TokenListeKorpus.Values[token] = '' then TokenListeKorpus.Values[token] := '1' else TokenListeKorpus.Values[token]:= inttostr(strtoint(TokenListeKorpus.Values[token]) + 1); end; end; function gibmirtoken(s:string; sep:char) :string; begin Result := Copy(s, 1, Pos(sep, s) - 1); { Funktion ermittelt aus tokenliste.zeile den zu zählenden "Ausdruck" der Zeile, die das folgendes Format hat: Ausdruck TAB EinUninteressantesWort TAB NochEinUninteressantesWort } end; |
Re: Wortliste erstellen: Zählroutine zu langsam
a) In einer sortierten Liste wird ein schnellerer Algorithmus zum Suchen verwendet.
b) Das Object-Property kann man schön für einen Integer verwenden, anstatt hier ständig die Strings/Zeilen für den Value-Zugriff zerlegen zu müssen. (Value und Name wird in nur einem String verwaltet und bei solchen Zugriffen jedesmal erneut zerlegt und zusammengesetzt) c) Und wenn die Anzahl nicht mehr als String gehalten wird, kann man sich auch noch die ganzen Integer<>String-Umwandlungen sparen. d) Var und Const ist bei Objeten nicht nötig ... es sei denn man will wirklich den Instantzeiger verändern und nicht nur den Inhalt
Delphi-Quellcode:
und in neueren Delphiversionen ginge auch sowas:
Procedure ZaehleAlleWoerterDerListe(TokenListe, TokenListeKorpus: TStringList);
var i, i2: Integer; token: String; begin for i := 0 to TokenListe.Count - 1 do begin token := GibMirToken(TokenListe[i], #9); i2 := TokenListeKorpus.IndexOf(Token); if i2 <= 0 then TokenListeKorpus.AddObject(token, TObject(1)) else TokenListeKorpus.Objects[i2] := TObject(Integer(TokenListeKorpus.Objects[i2]) + 1); end; end;
Delphi-Quellcode:
Die Tockenliste sollte natürlich entsprechend erstellt werden, damit sie auch optimal genutzt werden kann
Procedure ZaehleAlleWoerterDerListe(TokenListe, TokenListeKorpus: TStringList);
var i: Integer; S, Token: String; begin for S in TokenListe do begin token := GibMirToken(S, #9); i := TokenListeKorpus.IndexOf(Token); if i <= 0 then TokenListeKorpus.AddObject(token, TObject(1)) else TokenListeKorpus.Objects[i] := TObject(Integer(TokenListeKorpus.Objects[i]) + 1); end; end;
Delphi-Quellcode:
Integer(TokenListeKorpus.Objects[i]) enthält dann also die Anzahl zu dem Token mit dem Namen TokenListeKorpus[i] .
TokenListeKorpus := TStringList.Create;
TokenListeKorpus.Sorted := True; TokenListeKorpus.Duplicates := dupIgnore; |
Re: Wortliste erstellen: Zählroutine zu langsam
Vielen Dank! Das versuche ich mal umzusetzen.
Schönen Abend, frieder EDIT Ich bin baff, das ist ja ultraschneller! Ha, wieder was dazugelernt! Danke nochmals herzlich!! |
Re: Wortliste erstellen: Zählroutine zu langsam
Zitat:
z.B. hier mal das, welches sich hinter TokenListeKorpus.Values versteckt:
Delphi-Quellcode:
Da passiert also so Einiges.
procedure TStrings.SetValue(const Name, Value: string);
var I: Integer; begin I := IndexOfName(Name); if Value <> '' then begin if I < 0 then I := Add(''); Put(I, Name + NameValueSeparator + Value); end else begin if I >= 0 then Delete(I); end; end; function TStrings.GetValue(const Name: string): string; var I: Integer; begin I := IndexOfName(Name); if I >= 0 then Result := Copy(Get(I), Length(Name) + 2, MaxInt) else Result := ''; end; Und nochmal bezüglich dem "sortiert" ... die Funktion Find ist im Verhältnis zur Listengröße expotentiell schneller als der "normale" IndexOf:
Delphi-Quellcode:
function TStringList.IndexOf(const S: string): Integer;
begin if not Sorted then Result := inherited IndexOf(S) else if not Find(S, Result) then Result := -1; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:11 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