Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi String in TObjectList suchen (https://www.delphipraxis.net/182701-string-tobjectlist-suchen.html)

StepByStep 12. Nov 2014 08:53

Delphi-Version: XE2

String in TObjectList suchen
 
Guten Morgen z'sammen,

ich arbeite und lerne zur Zeit mit Delphi. Bei allen bis heute auftretenden Problemen, hat mir diese Community super geholfen und ich konnte meine Fehler immer finden und beseitigen, doch heute bräuchte ich mal Hilfe. Dazu schildere ich am besten mal mein Problem so gut wie es geht:

Ich habe ein Memofeld in den ich Text schreibe. Die einzelnen Wörter werden ausgelesen und in einen String geschrieben - natürlich nicht alle auf einmal. Sobald also ein vollständiges Wort in meinem String ist, soll in meiner TObjectList gesucht werden, ob es bereits vorhanden ist und wenn es das nicht ist, soll es mit einem Counter hinzugefügt werden. Es scheitert bei mir nicht an dem Hinzufügen, sondern an dem Abgleich, weil ich dort eine OutOfRange-Exception bekomme und ich mit den Lösungen im Internet nicht wirklich viel anfangen konnte. Ich schicke euch mal meinen jämmerlichen Ansatz, wie ich versuche den Abgleich zu machen. <embarassed>

Code:
repeat
    if TCharacter.isletter(sEingabe[iIndex]) then        // Solange das aktuelle Zeichen
    begin                                                // ein Buchstabe ist,
      sWort := (AnsiLowerCase(sWort) + sEingabe[iIndex]); // soll dieser zu sWort gefügt werden.
    end
    else
    begin
      iCounter := 0;
      if sWort <> '' then // Wenn es ein anderes Zeichen ist
      begin
        if List.Count = 0 then
        begin
          iAnzahl := 1;
          List.Add(TWort.create(AnsiLowerCase(sWort), iAnzahl));
          // Sobald es ein anderes Zeichen ist, soll sWort der TObjectList hinzugefügt werden
          // Erhöht die Häufigkeit um einen
          sWort := '';
        end
        else
        begin
          repeat
            if sWort = List[iCounter].sWort2 then <--------------- Hier meckert er!
            begin
              List[iCounter].iAnzahl := List[iCounter].iAnzahl + 1;
              // Erhöht die Häufigkeit um einen
              sWort   := '';
              iCounter := List.Count - 1;
            end
            else
            begin
              if List[List.Count - 1].sWort2 = '' then
              begin
                break;
              end
              else
              inc(iCounter);
            end;
          until iCounter = List.Count - 1;
        end;
        if sWort <> '' then
        begin
          iAnzahl := 1;
          List.Add(TWort.create(AnsiLowerCase(sWort), iAnzahl));
          // Sobald es ein anderes Zeichen ist, soll sWort der TObjectList hinzugefügt werden
          // Erhöht die Häufigkeit um einen
          sWort := '';
        end;
      end;
    end;
    inc(iIndex);
  until iIndex = Length(sEingabe) + 2;
__________________________________________________ __________________________________________________ _______________________________________________
(Verzeiht mir, wenn ich nicht die richtige Implementation gewählt habe, mein Browser spinnt gerade irgendwie. Ich kann nichtmals Smileys setzen...)

Also zur Erklärung: Der Obere Teil ist ja einfach nur das Auslesen und gucken, ob es ein Buchstabe ist oder nicht.
Danach soll er dann, weil ja zu Beginn noch kein Element in der List ist, das erste Wort ohne Abgleich reinschreiben. Sobald List.Count aber nicht mehr 0 ist, also ein Element vorhanden ist, soll er den neuen String mit den Elementen in der Liste vergleichen und bei einem Fund den Zähler für dieses Wort erhöhen.
Und wenn das Wort halt nicht drin ist, dann soll er es ganz normal hinzufügen - so weit der Plan.

Ich hoffe ich konnte das gut genug schildern und bedanke mich schonmal für eure Hilfe.

Gruß
Jan

mkinzler 12. Nov 2014 08:56

AW: String in TObjectList suchen
 
Der Index wird bei 0 beginne, dann ist der höchste Index Count-1

StepByStep 12. Nov 2014 08:59

AW: String in TObjectList suchen
 
Hallo mkinzler,

das fiel mir beim durchlesen auch ebengerade auf, ich hatte die -1 da eigentlich schon drin stehen, war jetzt selbst verwirrt...
Fehler gelangt nämlich jetzt an seine alte Position in die Zeile: if sWort = List[iCounter].sWort2 then

Gruß
Jan

mkinzler 12. Nov 2014 09:00

AW: String in TObjectList suchen
 
Hier Nicht:
Zitat:

Delphi-Quellcode:
if List[List.Count].sWort2


StepByStep 12. Nov 2014 09:06

AW: String in TObjectList suchen
 
Wie meinst du "Hier Nicht"? Das ist doch die einzige Stelle, wo es hingehören würde. Mir ist klar, dass die Indexposition bei 0 beginnt, aber außer dieser einen Zeile gäbe es doch sonst keine Möglichkeit.

Klaus01 12. Nov 2014 09:13

AW: String in TObjectList suchen
 
List.count ist zb. 3
Der Index ist aber dann von 0..2.
Daher ist List.count ein Index den es nicht gibt.

Grüße
Klaus

StepByStep 12. Nov 2014 09:21

AW: String in TObjectList suchen
 
Ich muss das glaube ich mal richtig verstehen...

Ich habe eine Liste mit 10 Elementen. Die geht dann von 0 bis 9.
Jetzt schreibe ich einen String mit seinem dazugehörigen Integerwert an die erste Stelle, also die 0te.
Wenn ich jetzt ein weiteres Element habe, dann soll er das, mit allen Indexpositionen vergleichen,
ob der String schon vorhanden ist. Das wollte ich mit iCounter machen, der bei 0 startet und dann sich erhöht bis
zu List.Count - 1, also dem höchsten Listenindex.

Aber habe ich deinen Fall nicht schon mit der -1 abgedeckt Klaus?

DeddyH 12. Nov 2014 09:39

AW: String in TObjectList suchen
 
Wäre es nicht einfacher, die Suche in eine eigene Methode auszulagern? Dazu könnte man entweder die Liste erweitern, oder man macht es zur Not von außen.
Delphi-Quellcode:
function TWasWeißIch.IndexOfToken(const Token: string): integer;
var
  idx: integer;
begin
  Result := -1;
  for idx := 0 to List.Count - 1 do
    if Token = List[idx].sWort2 then
      begin
        Result := idx;
        break;
      end;
end;
Gibt diese Funktion -1 zurück, ist das Wort nicht enthalten.

mkinzler 12. Nov 2014 09:49

AW: String in TObjectList suchen
 
Zitat:

Zitat von StepByStep (Beitrag 1279433)
Ich muss das glaube ich mal richtig verstehen...

Ich habe eine Liste mit 10 Elementen. Die geht dann von 0 bis 9.
Jetzt schreibe ich einen String mit seinem dazugehörigen Integerwert an die erste Stelle, also die 0te.
Wenn ich jetzt ein weiteres Element habe, dann soll er das, mit allen Indexpositionen vergleichen,
ob der String schon vorhanden ist. Das wollte ich mit iCounter machen, der bei 0 startet und dann sich erhöht bis
zu List.Count - 1, also dem höchsten Listenindex.

Aber habe ich deinen Fall nicht schon mit der -1 abgedeckt Klaus?

So wie es jetzt steht ja. Vorher stand aber was anderes.

StepByStep 12. Nov 2014 10:01

AW: String in TObjectList suchen
 
@mkinzler: Das hatte ich ja verbessert, s. #3

@DeddyH: Ich habe daraus zwar keine eigene Funktion gemacht, aber ich habe das Problem mit einer For-Schleife lösen können. Danke dafür. Er geht das jetzt auch alles richtig durch, doch jetzt wirft er mir während ich das eben gedebuggt habe eine Exception bei meinem Sortieralgorithmus aus...

Code:
procedure TForm1.Sort(var List: TObjectList<TWort>);
var
  iCounter, iHcounter, iPosition: integer;
  Temp:                          TWort;
begin
  iHcounter := 0;
  iCounter := 0;
  while iCounter < High(List[List.Count - 1].iAnzahl) do
  begin
    iPosition := iCounter;
    if iHcounter = High(List[List.Count - 1].iAnzahl) + 1 then
    begin
      inc(iCounter);
      iHcounter := iCounter;
    end
    else
    begin
      for iHcounter := iCounter + 1 to High(List[List.Count - 1].iAnzahl) do
      begin
        if (List[iHcounter].iAnzahl) > (List[iPosition].iAnzahl) then <----------- Siehe hier.
        // Sortiert die TObjectList nach der Häufigkeit
        begin
          Temp           := List[iHcounter];
          List[iHcounter] := List[iPosition];
          List[iPosition] := Temp;
        end;
      end;
      iHcounter := 0;
    end;
  end;
end;
Dies ist ebenfalls wieder eine OutOfRange-Exception, aber die verstehe ich nicht so ganz. iHcounter soll eine andere Indexposition haben als iPosition. Ich muss ja schließlich irgendwie die Zahlen zu den Strings sortieren und damit einhergehend vollständige Elemente der TObjectList, oder ist das falsch?

@Edit: Ich verlange nicht, dass ihr mir den kompletten Code vorschreibt, so lerne ich schließlich nicht... Ich brauche nur das Verständnis. Danke.

DeddyH 12. Nov 2014 10:06

AW: String in TObjectList suchen
 
TObjectList enthält bereits eine Sort-Methode, da böte es sich ja an, diese zu benutzen. Aber selbst wenn nicht: was versuchst Du mit dem High() zu ermitteln, mir ist das nicht klar?

Blup 12. Nov 2014 10:12

AW: String in TObjectList suchen
 
Schau mal in die Hilfe zu "High()" und dann überleg was "High(List[List.Count - 1].iAnzahl)" deiner Meinung nach zurück gibt.

StepByStep 12. Nov 2014 10:33

AW: String in TObjectList suchen
 
@DeddyH: Da stimme ich dir zu, wenn die TObjectList bereits einen Sortieralgorithmus besitzt, werde ich diesen auch nehmen. Bis dato wusste ich davon aber noch nicht.

@DeddyH & Blup: Mit dem High(...) möchte ich sagen, dass er von Beginn der List bis zum höchsten Indexwert durchgeht und sortiert - naja, zumindest habe ich mir das gedacht.

DeddyH 12. Nov 2014 10:43

AW: String in TObjectList suchen
 
Schau doch bitte mal nach: High().

StepByStep 12. Nov 2014 10:49

AW: String in TObjectList suchen
 
Zitat:

In Delphi können Sie mit High die Obergrenze eines Ordinal-, Array- oder ShortString-Wertes abrufen.
Also wenn ich das jetzt richtig verstanden habe, dann kann man diese Funktion sowieso nicht auf TObjectList übertragen.
Wenn das so ist, würde ja sowie so dein Vorschlag bezüglich der integrierten Sortiermethode greifen DeddyH.

Ich glaube jetzt muss ich mich da erstmal reinlesen, danke für die Hilfe bis hierhin.

Gruß
Jan

DeddyH 12. Nov 2014 11:01

AW: String in TObjectList suchen
 
iAnzahl dürfte ja ein Ordinaltyp (Integer?) sein. Also gibt High(List[List.Count - 1].iAnzahl) immer denselben Wert zurück, nämlich den des maximal möglichen für den Typ von iAnzahl, im Falle von Integer also MAXINT.

StepByStep 12. Nov 2014 11:50

AW: String in TObjectList suchen
 
Ja das ist richtig, iAnzahl ist ein Integer. Ich wollte aber gar nicht den Maximalwert der Integers wiedergeben, sondern den der TOjectList. :gruebel:
Ich hatte mir jetzt mal, die Sortierfunktion der TObjectList angeschaut, diese ist aber gar nicht anders als meine, kann das sein?

Mein Problem liegt daran, dass ich nicht genau weiß, wie ich auf die Richtige "Spalte" der TObjectList zugreife, also auf iAnzahl und danach sortiere und das richtig ausgebe... :glaskugel:

Sir Rufo 12. Nov 2014 12:19

AW: String in TObjectList suchen
 
Warum nicht einfach einen
Delphi-Quellcode:
IComparer<T>
Delphi-Referenz durchsuchenSystem.Generics.Defaults.IComparer der Liste übergeben?

Dann kann man ganz simpel mit Delphi-Referenz durchsuchenSystem.Generics.Collections.TList.Contains abfragen ob eine gleiche Instanz schon in der Liste enthalten ist.


DeddyH 12. Nov 2014 12:36

AW: String in TObjectList suchen
 
Die Sortierung an sich übernimmt die Liste selbst, Du musst nur die Vergleichsfunktion schreiben, die festlegt, wann ein Item "kleiner" als das andere ist. Diese Vergleichsfunktion kannst Du sogar beim Aufruf als anonyme Methode übergeben. Ungetestet:
Delphi-Quellcode:
List.Sort(TComparer<TWort>.Construct(
  function(const Left, Right: TWort): integer
  begin
    Result := Left.iAnzahl - Right.iAnzahl;
  end));
Für TComparer musst Du noch die Unit Generics.Defaults einbinden.

StepByStep 12. Nov 2014 12:56

AW: String in TObjectList suchen
 
Also das Vergleichen habe ich ja bereits mit DeddyH's Methode erfolgreich lösen können, die habe ich für meine Belange umgewandelt und integriert.
Einzig diese Sortierfunktion steht mir im Wege. Wobei ich glaube, dass es weniger die Funktion, als mein Verständnis dafür ist. :wall:

Zitat:

Die Sortierung an sich übernimmt die Liste selbst, Du musst nur die Vergleichsfunktion schreiben, die festlegt, wann ein Item "kleiner" als das andere ist. Diese Vergleichsfunktion kannst Du sogar beim Aufruf als anonyme Methode übergeben. Ungetestet:
markieren
Delphi-Quellcode:
List.Sort(TComparer<TWort>.Construct(
function(const Left, Right: TWort): integer
begin
Result := Left.iAnzahl - Right.iAnzahl;
end));
Für TComparer musst Du noch die Unit Generics.Defaults einbinden.
Wenn ich mir das so anschaue, würde ich gerne mal meine Gedanken dazu mitteilen und es wäre nett, wenn ihr sie ggf. berichtigt.
Ich habe eine Funktion mit zwei Variablen? des Typs TWort. Der Rückgabewert ist ein Integer.
Die Rechnung besagt: Links weniger rechts. Bsp.: 4, 9 - Dann sollte jetzt 9 mit 4 getauscht werden. Result = 5.

Aber was bringt mir dieses Result? Ich möchte im Enddefekt die nach der Anzahl sortierte Liste in einem weiteren Memofeld ausgeben.

DeddyH 12. Nov 2014 13:16

AW: String in TObjectList suchen
 
Die Vergleichsfunktion ist ein TComparison. Leider ist dieser in der Hilfe nicht sonderlich detailliert erklärt, aber Du kannst Dir auch TListSortCompare anschauen, die Funktionsweise ist ja die Gleiche, wenn mich nicht alles täuscht.

StepByStep 12. Nov 2014 14:04

AW: String in TObjectList suchen
 
Also, nach wie vor verstehe ich das nicht ganz. Weder das eine, noch das andere haben mir dabei geholfen.
Ich weiß nicht, wie ich das in meine Code einbinden muss... und je mehr ich mir durchlese, umso verwirrter bin ich.

Die dazugehörige Funktion muss ich doch irgendwo niederschreiben, erfolgt das in der class?

DeddyH 12. Nov 2014 14:29

AW: String in TObjectList suchen
 
Die Funktion steht doch schon in #19.

StepByStep 12. Nov 2014 14:41

AW: String in TObjectList suchen
 
Ja ich weiß, ich hatte dazu ja auch was geschrieben. Mein Problem ist einfach das Verständnis dafür.
Es wäre gut, wenn du mir vielleicht das ganze mal an einem Beispiel erklärst, weil ich stehe momentan echt auf dem Schlauch.

Ich habe also eine Liste mit zwei Elementen. Das erste hat einen Integerwert von 4 und das zweite Element hat einen Integerwert von 9.

Nach deinem Beispiel rechne ich jetzt '9-4' und das Ergebnis ist 5. Was genau bringt mir das aber jetzt? Was sagt diese 5 aus?
Diese Funktion muss ich aber doch gewiss irgendwo definieren/hinschreiben in meine Klasse oder nicht?

Entschuldigung... Ich bin gerade ziemlich begriffsstuzig. :oops:

Gruß
Jan

mkinzler 12. Nov 2014 14:46

AW: String in TObjectList suchen
 
Nicht das Ergebnis, sondern das Vorzeichen ist wichtig.
Ergebnis positiv: 1. Wert ist größer
Ergebnis 0: beide Werte gleich
Ergebnis negativ: 2. Wert ist größer

StepByStep 12. Nov 2014 14:54

AW: String in TObjectList suchen
 
Hm ok, das habe ich verstanden. Das funktioniert dann ja wahrscheinlich mit if-Anweisungen, aber wo passiert der eigentliche Tausch? In einer vordefinierten Funktion?

DeddyH 12. Nov 2014 15:13

AW: String in TObjectList suchen
 
Der Tausch erfolgt intern in der Sort-Methode der Liste.

StepByStep 12. Nov 2014 15:33

AW: String in TObjectList suchen
 
Hm... ich habe das zwar jetzt integriert bekommen, aber es kommen noch mehr Fehler.

Code:
  List.Sort(TComparer<TWort>.Construct(
    function(const Left, Right: TWort): integer
    begin
      Result := Left.iAnzahl - Right.iAnzahl;
    end));
  iAusgabe    := 0;
  for iAusgabe := List[iAusgabe].iAnzahl to List[List.Count - 1].iAnzahl do
    Memo2.Lines.Add(IntToStr(List[iAusgabe].iAnzahl) + 'x ' + List[iAusgabe].sWort2);
Erstmal, wenn ich in mein erstes Memo "Memo Meme Meme" eintippe, dann erfolgt in der Ausgabe, dem zweiten Memofeld, nur 2x meme, aber "1x memo" fehlt und ich bekomme wieder eine Exception. Ich hatte via Debugger mal in die Liste geschaut und auf Indexposition 0 stand immer noch Memo und auf 1 stand Meme... sollten die nicht getauscht werden? Reingeschaut hatte ich kurz vor der Ausgabe. Danke nochmal für eure Geduld.

DeddyH 12. Nov 2014 15:49

AW: String in TObjectList suchen
 
Was hat denn der Wert einer Eigenschaft eines Eintrags mit der tatsächlichen Anzahl der in der Liste vorhandenen Einträge zu tun?

StepByStep 12. Nov 2014 15:55

AW: String in TObjectList suchen
 
Zitat:

Was hat denn der Wert einer Eigenschaft eines Eintrags mit der tatsächlichen Anzahl der in der Liste vorhandenen Einträge zu tun?
Wenn du so fragst vermutlich nichts, aber ich möchte mit der Zeile

Code:
Memo2.Lines.Add(IntToStr(List[iAusgabe].iAnzahl) + 'x ' + List[iAusgabe].sWort2);
nur aussagen, dass die Anzahl dem entsprechenden Wort zugeordnet wird. Deine Aussage war doch bestimmt auf die Zeile bezogen, oder?
Irgendwie muss ich ja die Werte untereinander in dieses Memofeld schreiben.

DeddyH 12. Nov 2014 15:58

AW: String in TObjectList suchen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab mal schnell unter XE eine kleine unkommentierte Demo geschrieben.

Sir Rufo 12. Nov 2014 15:58

AW: String in TObjectList suchen
 
Könntest du für Delphi-Code auch die Delphi-Tags benutzen?

Zitat:

Zitat von StepByStep (Beitrag 1279497)
Hm... ich habe das zwar jetzt integriert bekommen, aber es kommen noch mehr Fehler.

Delphi-Quellcode:
  List.Sort(TComparer<TWort>.Construct(
    function(const Left, Right: TWort): integer
    begin
      Result := Left.iAnzahl - Right.iAnzahl;
    end));
  iAusgabe    := 0;
  for iAusgabe := List[iAusgabe].iAnzahl to List[List.Count - 1].iAnzahl do
    Memo2.Lines.Add(IntToStr(List[iAusgabe].iAnzahl) + 'x ' + List[iAusgabe].sWort2);

Den Comparer würde ich so definieren:
Delphi-Quellcode:
uses
  Math;

TComparer<TWort>.Construct(
  function (const L, R : TWort ) : Integer
  begin
    Result := CompareValue( L.iAnzahl, R.iAnzahl );
  end );
und das verstehe ich irgendwie überhaupt nicht
Delphi-Quellcode:
  iAusgabe    := 0;
  for iAusgabe := List[iAusgabe].iAnzahl to List[List.Count - 1].iAnzahl do
    Memo2.Lines.Add(IntToStr(List[iAusgabe].iAnzahl) + 'x ' + List[iAusgabe].sWort2);
Nehmen wir an, du hast dort 3 Einträge und der erste Eintrag beinhaltet in iAnzahl eine 5, dann versuchst du auf das 5. Element der Liste zuzugreifen, was es logischerweise gar nicht gibt ... sehr seltsam

StepByStep 13. Nov 2014 06:59

AW: String in TObjectList suchen
 
Guten Morgen,

@Sir Rufo: Wenn ich den Rückgabewert der Funktion wegnehme, dann meckert er, dass er einen ":" erwartet.
Zu folgenden Zeilen:

Delphi-Quellcode:
  iAusgabe    := 0;
  for iAusgabe := List[iAusgabe].iAnzahl to List[List.Count - 1].iAnzahl do
    Memo2.Lines.Add(IntToStr(List[iAusgabe].iAnzahl) + 'x ' + List[iAusgabe].sWort2);
iAusgabe ist quasi mein Index. Dieser soll vom niedrigsten bis zum höchsten Wert durchlaufen und entsprechend für jeden Indexwert die dort enthaltene Anzahl und das Wort in das Memofeld schreiben. Kann es vielleicht sein, dass ich TObjectLists falsch verstanden habe?

Für mich ist das eine Liste von 0 bis n. Da ich Integer- und Stringwerte habe, gibt es zwei Spalten, die nebeneinander sind. Und ich kann doch über einen Indexwert darauf zugreifen oder etwa nicht?

Zoot 13. Nov 2014 07:08

AW: String in TObjectList suchen
 
hast du also eigentlich folgendes im Sinn?


Delphi-Quellcode:
 
  for i := 0 to List.Count - 1 do
    Memo2.Lines.Add(IntToStr(List[i].iAnzahl) + 'x ' + List[i].sWort2);

Sir Rufo 13. Nov 2014 07:10

AW: String in TObjectList suchen
 
Das mit ohne dem Rückgabewert war falsch (ist im Beitrag korrigiert).

Nehmen wir an, du hast folgende Liste
IndexsWortiAnzahl
0hallo2
1du5
2da7
dann ergibt sich daraus, dass
Delphi-Quellcode:
iAusgabe
von
Delphi-Quellcode:
2..7
läuft.

Zeige mir doch mal in der Liste die Zeilen mit dem Index
Delphi-Quellcode:
3..7
die sind nicht da!

Verstehen könnte ich
Delphi-Quellcode:
for iAusgabe := 0 to List.Count -1 do
, weil dann läuft
Delphi-Quellcode:
iAusgabe
von
Delphi-Quellcode:
0..2
und das sind gültige Index-Werte.

PS So ein Debugger leistet tolle Arbeit, wenn man den benutzt und sich einfach während des Ablaufs die Variablenwerte anschaut.

StepByStep 13. Nov 2014 07:30

AW: String in TObjectList suchen
 
Ich bedanke mich für eure Hilfe, die Erklärung zu dem Index der TObjectList hat mir gerade sehr geholfen. Ich lese richtig aus und zähle auch richtig. Danke nochmals. :)

Gruß
Jan


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:39 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