Autor Beitrag
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 10.02.13 10:15 
Hallo,
ich benötige wieder einmal eine gute Idee.
Ich habe eine sortierte Stringliste der Form (Ausschnitt)
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
...
Abendweite    8705
Aberration    8701
abessinische Bauernmultiplikation    102
abgekantete Polyeder    3145
abgekantete Polyeder (2)    3146
abgekantetes 5-Zell    3955
abgekantetes 8-Zell    3958
abgerundete Zahlen    1257
abgeschlossene Kugel    4489
abgeschlossene Menge    61
abgeschlossene Verknüpfung    663
abgeschlossener topologischer Raum    4490
abgeschlossenes Intervall    89
abgeschnittener Sternwürfel    3729
...

die im Moment 16000 Einträge enthält (in Zukunft weiter wachsend). Die Begriffe sind von den Zahlangaben mit einem Tabulator getrennt.
Mein Problem ist, dass ich möglichst schnell einen Eintrag finden möchte. Bisher durchsuche ich die ganze Stringliste nach einem Begriff s mit
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
gefunden:=false;
j:=0;
repeat
  if pos(s,liste[j])=1 then gefunden:=true;
  inc(j);
until gefunden or (j>liste.Count-1);

Der gefundene Eintrag wird anschließend in Begriff und Zahl zerlegt. Das funktioniert an sich, ist aber gerade für Strings mit Anfangsbuchstaben am Ende des Alphabets ziemlich langsam.

Die Listenfunktion indexof(s) bringt leider nichts, da dort nur nach dem ganzen String gesucht wird.
Problematisch ist außerdem, dass auch Einträge mit Umlauten als Anfangsbuchstaben auftreten und die Liste bei verschiedenen Windows-Versionen (XP, Vista, 7) unterschiedlich sortiert wird; jedenfalls auf meinen Testrechnern. Ich verstehe es zwar nicht, aber es ist so.
Ein Zerlegen der Liste in zwei Listen, zum einen in die Begriffe, zum anderen in die Zahlen, ist mir gerade wegen der Sortierung bisher nicht geglückt. Außerdem muss der gesuchte Begriff genau mit dem Listeneintrag übereinstimmen.
Suche ich z.B. in meinem Beispiel oben den Begriff "Menge", so darf nicht "abgeschlossene Menge" als Lösung gefunden werden, sondern der wesentlich später folgende Eintrag "Menge".

Sieht jemand von Euch eine Möglichkeit, wie ich die Suche beschleunigen kann. Danke.

Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: So 10.02.13 10:33 
Hallo,

eine Stringlist hat die Eigenschaft .sorted, die man auf true setzen kann.
docs.embarcadero.com...ringList_Sorted.html
Dann ist .find anwendbar und schnell, da es binäre Suche anwendet.
docs.embarcadero.com...ses_TStringList.html
oder hier:
www.delphibasics.co....asp?Name=TStringList
Für Deinen speziellen Fall müsstest Du ein CostumSort erstellen.
www.entwickler-ecke....highlight=customsort

Gruß Horst

Für diesen Beitrag haben gedankt: Mathematiker
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: So 10.02.13 10:50 
Wenn ich das richtig verstanden habe, soll als Suchbegriff auch ein Teilstring (der aber am Anfang stehen muss) zulässig sein. AFAIK vergleicht Find aber den gesamten String. Somit wird wohl nichts anderes übrig bleiben, als eine eigene binäre Suche zu implementieren, die dann mit AnsiStartsText/AnsiStartsStr den jeweiligen Stringanfang vergleicht.

Für diesen Beitrag haben gedankt: Mathematiker
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 10.02.13 11:15 
Hallo,
Danke für beide Antworten.
Tstringlist.find ist eine schöne, da schnelle Sache. Leider hilft es mir nicht wirklich, da auch hier wieder der gesuchte String absolut identisch sein muss. Und durch die vor der Suche unbekannten Zahlen wird leider nichts gefunden.

Die Idee mit AnsiStartsText/AnsiStartsStr würde wahrscheinlich etwas beschleunigen. Nur leider kennt mein Delphi 5 in der Strutils diese Anweisungen noch nicht.
Die binäre Suche habe ich schon selbst versucht umzusetzen. Die "doofen" Umlaute haben bisher stets gestört. Ich werde weiter experimentieren.

Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: So 10.02.13 11:37 
Ich will keine Rechte verletzen, deshalb poste ich hier keinen Original-Code. Als Tipp sei aber gesagt, dass AnsiStartsText intern auf die API-Funktion CompareString zurückgreift.

Für diesen Beitrag haben gedankt: Mathematiker
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 10.02.13 11:43 
Hallo,
Ich habe jetzt eine zweite zusätzliche Liste erstellt, die nur die Begriffe enthält. Das verzögert zwar etwas den Programmstart, aber die Suche wird deutlich schneller.

Verrückt ist nur, dass beim Kopieren der Begriffe aus einer sortierten liste1 in eine sortierte liste2 sich die Reihenfolge der Begriffe durch das fehlende Tabulatorzeichen ändert!
Daraufhin habe ich bei der 2.Liste sorted=false gelassen. Tstringlist.find funktioniert trotzdem, bis jetzt!
Das ist alles etwas merkwürdig.

Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: So 10.02.13 12:28 
Die Frage ist, ob deine Daten überhaupt so sinnvoll gespeichert sind. Für mich klingt dein Problem total nach einer Hashtabelle (suchen geht dann sozusagen "sofort"). Eine Hashtable braucht beim Vergrößern allerdings O(n) (also solange wie deine Suche, alle durchzuprobieren). Das kommt aber nicht so oft vor, und ich denke da kann man auch noch was machen, kommt auf dein Lastprofil an.

Interessant wären folgende Punkte:
-wie oft musst du suchen
-suchst du immer nach dem String, oder auch nach der Zahl?
-welche Werte musst du auslesen können?
-wie oft, wieviel musst du denn Einfügen
(binäre Suche und schnelles Einfügen widerspricht sich irgendwie, eine Hashtabelle kann aber beides...solange noch Platz ist ;) )

Bzgl hashtable kannst du mal hier gucken:
www.entwickler-ecke....ewtopic.php?t=102753 (XVHashing.pas).
Die sollte mittlerweile fehlerfrei sein, hab die ich schon ziemlich oft verwendet (mit zum Teil über 1Mio Einträgen). Ich würde dann noch was dazu schreiben, wenns in die richtige Richtung geht ;)

PS: Die Hashtabelle aufbauen dauert natürlich auch etwas, wenn du also die sortierte Liste irgendwoher bekommst und nur einmal suchen willst, macht es keinen Sinn, eine Hashtabelle zu benutzen.

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)

Für diesen Beitrag haben gedankt: Mathematiker
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19313
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 10.02.13 12:44 
Wie wäre es mit THashedStringList, die bei Delphi dabei ist? (Ich weiß nicht seit welcher Version, aber jedenfalls schon länger.)

Da bei dir Delphi 5 steht, wird das wohl nicht in Frage kommen, aber in einigermaßen aktuellen Delphiversionen (2009+) gibt es auch noch TDictionary, das noch einmal sehr viel schneller ist.

Für diesen Beitrag haben gedankt: Martok, Mathematiker
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 10.02.13 13:09 
Wenn Du hinten immer nur eine Zahl hast würde ich die garnicht mit in den String schreiben sondern in Object. Also entweder sl.AddObject(String, Zahl) verwenden, oder sl.Objects[sl.Add('bla')]. Wobei sl die StringListe ist. Dann kannst Du einfach mit einer sortierten Liste (sl.Sorted=true) arbeiten und hast das Problem mit dem Tabulatorzeichen nicht. Denn das brauchst Du ja nicht mehr. Um den Speed beim reinfüllen zu erhöhen kann man die zu erwartende Größe (Anzahl der Datensätze) der Liste vorher mit Capacity festlegen.
Allerdings würde ich immer einer MemTable den Vorzug geben, was aber bei deiner alten Delphi Version ein bisschen eng wird, da kaum noch unterstüzt. Selbst mein D7 fällt immer mehr raus *heul*.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?

Für diesen Beitrag haben gedankt: Mathematiker
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 10.02.13 13:29 
Hallo Xion,
user profile iconXion hat folgendes geschrieben Zum zitierten Posting springen:
-wie oft musst du suchen
-suchst du immer nach dem String, oder auch nach der Zahl?
-welche Werte musst du auslesen können?
-wie oft, wieviel musst du denn Einfügen

Die Liste enthält Schlagwörter eines Lexikons. Die angegebenen Zahlen sind die Seitenzahlen mit dem entsprechenden Begriff. Deshalb kann ich schlecht einschätzen, wie oft zu suchen ist. Je nach Nutzer werden die Links zu den Seiten mehr oder weniger genutzt.
Praktisch muss ich nur nach den Begriffen suchen. Die Seitenzahlen werden ohne Suche direkt aufgerufen.
user profile iconXion hat folgendes geschrieben Zum zitierten Posting springen:
Bzgl hashtable kannst du mal hier gucken:
www.entwickler-ecke....ewtopic.php?t=102753 (XVHashing.pas).

Danke. Das finde ich sehr interessant und werde es mir heute noch genau ansehen.

Hallo Jaenicke,
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wie wäre es mit THashedStringList, die bei Delphi dabei ist?

Bei Delphi 5 gibt es THashedStringList noch nicht.
Irgendwann muss ich wohl auf ein modernes Delphi umsteigen. Aber ich liebe mein Delphi 5 geradezu. :lol:

Hallo Sinspin,
user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Wenn Du hinten immer nur eine Zahl hast würde ich die garnicht mit in den String schreiben sondern in Object. Also entweder sl.AddObject(String, Zahl) verwenden, oder sl.Objects[sl.Add('bla')]. Wobei sl die StringListe ist.

Danke. Auch das klingt sehr gut. Mit dieser Art von Objekten habe ich noch gar keine Erfahrung. Muss ich mir unbedingt ansehen, denn das erscheint mir am schnellsten umsetzbar.

Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 10.02.13 14:07 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:

Hallo Sinspin,
user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Wenn Du hinten immer nur eine Zahl hast würde ich die garnicht mit in den String schreiben sondern in Object. Also entweder sl.AddObject(String, Zahl) verwenden, oder sl.Objects[sl.Add('bla')]. Wobei sl die StringListe ist.

Danke. Auch das klingt sehr gut. Mit dieser Art von Objekten habe ich noch gar keine Erfahrung. Muss ich mir unbedingt ansehen, denn das erscheint mir am schnellsten umsetzbar.

Nee, ich meine nichtmal das Du Objekte benutzt. Sondern dass du einfach nur den Pointer auf das Objekt (was Du ja nicht anlegst) misbrauchst. Ein Pointer oder Zeiger auf ein Objekt ist ja auch nur eine Zahl, Typ Integer(Cardinal) in der Regel. Die Zahl wird halt sonst nur als Adresse im Speicher verstanden, in deinem Fall nimmst Du die Zahl direkt.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: So 10.02.13 14:19 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
die im Moment 16000 Einträge enthält (in Zukunft weiter wachsend).

Da könnte man schon langsam über den Einsatz einer Datenbank nachdenken.

Für diesen Beitrag haben gedankt: FinnO, Nersgatt
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: So 10.02.13 15:52 
Also wenn der Nutzer suchen soll, dann würde ich auch eine Datenbank bevorzugen. Im Gegensatz zur Hashtabelle kommt die Datenbank auch mit Teiltexten klar (wenn man z.B "Bauernmultiplikation" sucht). Mit SQLite z.B. brauchst du auch keine Treiber und andren Kram zu installieren. Die Datenbank ist dann nur eine Datei und eine .dll.
Die Hashtabelle kommt mir zudem nicht mehr so geeignet vor, weil du sagst dass nur der Nutzer sucht (ich dachte eher ein Algorithmus sucht sehr oft). Die Hashtabelle muss ja erstmal aufgebaut werden, also alle Einträge müssen abgelegt werden. Bei einer Datenbank musst du das nur einmal machen (nicht bei jedem Programmstart). Ist auch viel speicherfreundlicher ;)

evtl. Problem: Wenn sich das Inhaltsverzeichnis ändert (von außen), dann müsstest du die Datenbank neu aufbauen. Wenn du selbst das Inhaltsverzeichnis änderst, wäre es natürlich kein Problem. Kommt ganz drauf an, wo das Inhaltsverzeichnis her kommt und wer es verändert.

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: So 10.02.13 16:12 
Wenn das ganze Zeugs auch irgendwo gespeichert werden soll, erscheint auch mir eine DB sinnvoll. Trotzdem habe ich mir mal den Spaß gemacht und unter Delphi 5 ein kleines Testprogrämmchen mit einer Binärsuche geschrieben. Wirklich langsam kommt mir persönlich das nicht vor.
Einloggen, um Attachments anzusehen!

Für diesen Beitrag haben gedankt: Mathematiker
Mathematiker Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 10.02.13 16:23 
Hallo,
gegenwärtig habe ich Folgendes schon probiert:

1. meine Anfangslösung ... zu langsam
2. eine zweite Liste ... einfach und schnell
3. user profile iconSinspins Hinweis auf addobject ... elegant und sehr schnell; vor allem entfällt das anschließende Zerlegen des Eintrags in Begriff und Seitenzahl

user profile iconXions Vorschlag mit der Hashtabelle werde ich probieren. Dazu muss ich das aber erst einmal besser verstehen.
Die Idee mit der Datenbank wird wohl effektiv sein, da nur ich die Liste verändere. Das werde ich auf jeden Fall versuchen.
Aber am reizvollsten und wahrscheinlich sehr schnell (muss ich noch ausführlich testen) ist die binäre Suche von user profile iconWasWeißDennIch. Damit muss ich nicht unbedingt auf eine Datenbank zugreifen. Die mag ich nämlich nicht. Erklären kann ich die Abneigung allerdings nicht.

Besten Dank an WasWeißDennIch für den Beispiel-Quelltext.
Vielen Dank für die vielen Hinweise an alle.

Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19313
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 10.02.13 18:43 
user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Nee, ich meine nichtmal das Du Objekte benutzt. Sondern dass du einfach nur den Pointer auf das Objekt (was Du ja nicht anlegst) misbrauchst. Ein Pointer oder Zeiger auf ein Objekt ist ja auch nur eine Zahl, Typ Integer(Cardinal) in der Regel. Die Zahl wird halt sonst nur als Adresse im Speicher verstanden, in deinem Fall nimmst Du die Zahl direkt.
Wobei man dabei dann bei Umstellung auf 64-Bit irgendwann mal heftige und schwer zu findende Probleme bekommen kann. Casten von Zahlen auf Objektpointer usw. ist ganz schlechter Programmierstil...

Wenn, dann kann man kleine Objekte nehmen, die nur einen solchen Wert enthalten, das ist kaum langsamer, kann aber schwerer Probleme verursachen.
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: So 10.02.13 19:40 
Also ich sehe überhaupt keine Verzögerung beim Sortieren, nur irgendwie ist die Suchfunktion nicht immer korrekt. Aber das ist ja bloß ein Test.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: So 10.02.13 19:52 
user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
nur irgendwie ist die Suchfunktion nicht immer korrekt.

Hast Du da gerade mal ein Beispiel?
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Mo 11.02.13 14:44 
Hallo,

das dictionary ist eindeutig das schnellste.Du musst nur eine gute Hashfunktion für die Strings finden, um einen guten key zu erzeugen( Strings-> Longint oder word)
Auf Delphi-Praxis gab es die Frage auch mal in Bezug auf 64Bit Zahlen.
www.delphipraxis.net/1159805-post14.html
Mit einer Zeit von 7 Sekunden für das Einfügen von 10e6 Werten kann man wohl leben.16e3 sollten also in 12 ms gespeichert sein.
Der Zugriff über den Key ist dann sozusagen sofort.
Xion's Hashtable sollte also eine wesentliche Beschleunigung bringen.

Gruß Horst
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Mo 11.02.13 18:00 
user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconTranx hat folgendes geschrieben Zum zitierten Posting springen:
nur irgendwie ist die Suchfunktion nicht immer korrekt.

Hast Du da gerade mal ein Beispiel?


Ich hatte es mit "drei" im Editfeld versucht, aber es kam nicht immer die erste Zahl mit "drei". Und wenn ich "Drei 6" eingab, kam als Suchwert "drei6" das hat er dann garnicht gefunden.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.