![]() |
TStringList - Anzahl der Wörter zählen
Hallo DP!
Ich wende mich mal wieder mit einer Problemstellung an Euch: Ich habe eine TStingList namens Woerter und AnzWoerter (in die ich die Anzahl/Häufigkeit der Woerter speichern möchte). Ich sehe mit der Function TOLIST(S:String):Boolean; nach, ob der String/das Wort in der Liste ist und wird eingefügt, wenn es nicht vorhanden ist. jetzt ist der String/das Wort aber schon vorhanden und möchte eigentlich ein Zähler zur Stringliste hinzufügen. Kann ich die TstingList 2 Dimensional erstellen, so dass die Werte nicht durcheinander kommen. Im Übrigen ist woerter.sorted:=True gesetzt. Hier mein schrecklicher Code:
Delphi-Quellcode:
Hat jemand einen Lösungsansatz?
Function ToList(const S:String):Boolean;
var i,x:Integer; flag:Boolean; index:integer; begin result:=false; // String gefunden, dann Zähler erhoehen. if woerter.Find(s,index) then begin X:=StrToInt(Anzwoerter[index]);INC(x);AnzWoerter[index]:=inttostr(x); exit; end; // Wenn nichts gefunden wurde: woerter.Add(s); // Wir wissen den Index woerter.Find(s,index); // Hier der Code der die Liste AnzWoerter durcheinander bringt. // Wie kann ich die Liste synchronisieren? anzwoerter.Add('1'); result:=true; end; Beste Grüße! Go2EITS |
Re: TStringList - Anzahl der Wörter zählen
Dann würde ich einen Record für die Einträge und diese mit einer eigenen List-Klasse verwalten (bzw. ObjectList)
|
Re: TStringList - Anzahl der Wörter zählen
Hallo,
Du benötigst nur ein TStringList Objeckt. Glücklicherweise kann zu jedem Eintrag in TStringList ein Referenz auf ein TObject speichern. Schau mal in OH unter TStringList.AddObject und TStringList.Objects nach. In letzter Konsequenz handelt es dabei nur einen Zeiger. Da ein Zeiger aber nichts anderes als 4 Byte sind kann man dort mit etwas Typcasting auch einen Integerwert speichern. z.B.
Delphi-Quellcode:
Mit TObject(Anzahl) kannst Du dem Compiler vergaukeln das es sich um eine Objektreferenz handelt.
sl.AddObject('Wort',TObject(Anzahl))
Beim Lesen muss Du aber wieder in einen Integer casten
Delphi-Quellcode:
var
Anzahl : Integer; ... Anzahl:=Integer(sl.Objects[aIndex]) |
Re: TStringList - Anzahl der Wörter zählen
@Mkinzler
Das mit der TStringlist war praktisch: Der woerter.found-Befehl war 100x schneller als meine Suche in der Liste mit "for i:=1 to Anzahl_Woerter do.." und der "Exit if found" Kombination. Zudem war keine Sortierroutine notwendig, weil die Eigenschaft Sorted schon vorhanden ist. Für den Record müsste ich Quicksort einbauen, wo doch meine Liste doch eigentlich schon fast fertig ist. :cry: @jens Schuman Also den Integer zu String und zurück habe ich schon drin. Siehe Code. OOP ist nicht so mein Ding. Das Problem: ich füge das Wort: 'that' in die Liste mit woerter.add ein. Es wird wird automatisch einsortiert. Nun muss ich auch einen Eintrag in AnzWoerter einfügen. Ok. Mache ich mal mit AnzWorter.Add('1'); Es wird am Ende eingefügt. Als Lösungsansatz sehe ich möglicherweise, dass ich den letzen Eintrag in der Liste AnzWoeter nehmen muss und ab INDEX 'That' alle Werte nach oben schiebe damit am INDEX/Position 'that' gesetzt werden kann und meine AnzWoerter wieder die richtigen Werte zu den in Woerter befindlichen Liste passen. Vielen Dank für Eure Antworten. :thumb: Ich benötige aber leider noch weitere Überlegungen. |
Re: TStringList - Anzahl der Wörter zählen
Hi,
ich weiß zwar nicht genau warum OOP nicht dein Ding ist, aber da du nicht etwas generelles gegen Klassen hast (du verwendest ja eine TStringList) solltest du doch die Variante von Jens vorziehen. An sich ist es natürlich sauberer ein Integer in einem Wrapper auch wirklich als Objekt zu übergeben. Klar, hier eine Referenz eh ein Integer, aber wenn Delphi mal etwas typsicherer wird... Jedenfalls zeigt dir Jens Lösung, dass du mit einer Liste auskommst. Du hast eine Art Dictonary. Hier wird ein Tupel (Schlüssel, Wert) abgespeichert. Anhand von Schlüssel kannst du dir den gespeicherten Wert zurückgeben lassen. Wird die Liste z.B. sortiert, bleibt diese Zuordnung automatisch erhalten. Wenn du hier noch ein THashedStringList verwendest (ein Nachfahre der TStringList) dürfte sich auch dir Perfomance noch einmal ordentlich verbessern. Als einfaches Beispiel:
Delphi-Quellcode:
Hier siehst du, dass du mit einer Liste auskommst. Es ist jetzt egal was du mit der Liste machst, die Zuordnung String -> Anzahl würde immer erhalten bleiben (beim Einfügen, Löschen, Sortieren, ...). Mittels AddObject legst du einfach an der Stelle des Strings einen Verweis auf ein Objekt ab. Dieser Verweis bleibt immer erhalten. Wie man damit arbeitet hat dir Jens eigentlich schon gezeigt, hier ist einfach nur ein Wrapper zu gegekommen.
type
TIntegerWrapper = class(TObject) private FValue : Integer; public Value : Integer read FValue write FValue; end; ... procedure toList(const s : String; const List : TStringList); var buffer : TIntegerWrapper; begin if assigned(List) then begin if List.indexOf(s) > -1 then begin buffer := TIntegerWrapper(List.Objects[List.indexOf(s)]); buffer.Value := buffer.Value + 1; end else begin buffer := TIntegerWrapper.Create; buffer.Value := 1; List.AddObject(s, buffer); end; end; end; // procedure toList(const s : String; const List : TStringList); Gruß Der Unwissende |
Re: TStringList - Anzahl der Wörter zählen
Ich habe ein wenig studieren müssen, bis verstande habe, was Ihr mir da anbietet.
Den Testcode habe ich mal reingestellt."Property" habe ich dem Code hinzufügt.
Delphi-Quellcode:
Es klappt leider nicht. Ich bekomme hier nur eine große Zahl, aber keine 1.
type
TIntegerWrapper = class(TObject) private FValue : Integer; public property Value : Integer read FValue write FValue; end; var Form1: TForm1; VAR w,a:TStringList; var i:Integer; var Anzahl : Integer; implementation procedure toList(const s : String; const List : TStringList); var buffer : TIntegerWrapper; begin if assigned(List) then begin if List.indexOf(s) > -1 then begin buffer := TIntegerWrapper(List.Objects[List.indexOf(s)]); buffer.Value := buffer.Value + 1; end else begin buffer := TIntegerWrapper.Create; buffer.Value := 1; List.AddObject(s, buffer); end; end; end; // procedure toList(const s : String; const List : TStringList); {$R *.dfm} begin w:=TStringList.Create; Anzahl:=0; Tolist('Das',w); for i:=0 to w.count-1 do begin ShowMessage(w[i]); Anzahl:=Integer(w.objects[i]); ShowMessage(IntToStr(anzahl)); end; FreeAndNil(w); end. Ich gehe davon aus, das ich auch ein int64 nehmen kann. |
Re: TStringList - Anzahl der Wörter zählen
Hallo Go2EITS,
in Objects[] befinden sich die Wrapper-Objekte, keine Integer-Werte:
Delphi-Quellcode:
Du solltest außerdem nicht vergessen, vor der Freigabe der Stringliste die Wrapper-Objekte freizugeben.
Anzahl := TIntegerWrapper(w.Objects[i]).Value;
Zitat:
|
Re: TStringList - Anzahl der Wörter zählen
Funzt! Spitze!
Sorry, wie gebe ich das Object frei in meinem Fall. (Null Ahnung hab!) Heißt dass, ich ein Freeandnil(w.objects) machen muss? :gruebel: |
Re: TStringList - Anzahl der Wörter zählen
Hallo,
ich finde den TIntegerWrapper hier nicht so gut. Es gehört zu den best practices eines framework designers jeder Klasse eine tag property mitzugeben, wenn diese Klasse keine rein interne Funktion hat. Mal ist diese property eine Integer (Tag), mal ein Pointer (Data) und mal ein TObject. Es wurde jeweils der Typ gewählt, der am sinnvollsten erschien - alle anderen Typen müssen über einen type cast passend gemacht werden. Das ist nichts verwerfliches und es genügt, wenn der type cast geeignet gekapselt wird. Der Wrapper bringt in diesem konkreten Fall Mehraufwand, dem kein Nutzen gegenüber steht.
Delphi-Quellcode:
Grüße vom marabu
function GetCount(sl: TStrings; const s: String): Integer;
var index: Integer; begin index := sl.IndexOf(s); if index < 0 then Result := 0 else Result := Integer(sl.Objects[index]); end; procedure SetCount(sl: TStrings; const s: String); var index: Integer; begin index := sl.IndexOf(s); if index < 0 then sl.AddObject(s, Pointer(1)) else sl.Objects[index] := Pointer(Succ(Integer(sl.Objects[index]))); end; procedure TDemoForm.DemoButtonClick(Sender: TObject); var sl: TStringList; i: Integer; begin sl := TStringList.Create; sl.Sorted := True; sl.Duplicates := dupIgnore; SetCount(sl, 'so'); SetCount(sl, 'oder'); SetCount(sl, 'So'); ListBox.Clear; for i := 0 to Pred(sl.Count) do ListBox.Items.Add(Format('%s = %d', [sl[i], GetCount(sl, sl[i])])); sl.Free; end; |
Re: TStringList - Anzahl der Wörter zählen
@marabu
Da staune ich aber: Wenn das so ist! Ich habe zu wenig Ahnung mit Wrappern. Das übernehme ich so. Danke für Deine Mühe mir fertigen und funktionierenden Code zu liefern. Das hätte ich nie so hingebracht. Jetzt verstehe ich den Zusammenhang von TStringList und Objects besser. @Hawkeye219 Nett, dass Du meinen Code durchgesehen hast und mir die Lösung gebracht hattest. @Der_Unwissende Vielen Dank für Deine Hilfe und dass Du bei mir immer reinsiehst und Hilfestellung leistest. Beste Grüße an alle "Helfer." Go2EITS |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:05 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