Was ist der schnellste Weg, um in Delphi nach einem Schlüsselwort in einer Schlagwortliste zu suchen?

7

Ich habe eine kleine Liste von Keywords. Was ich wirklich gerne machen würde, ist ähnlich wie:

%Vor%

Leider kann die CASE-Anweisung nicht so wie für Strings verwendet werden.

Ich könnte das direkte IF THEN ELSE IF-Konstrukt verwenden, z.B.:

%Vor%

aber ich habe gehört, das ist relativ ineffizient.

Was ich stattdessen gemacht habe, ist:

%Vor%

Das ist natürlich nicht der beste Programmierstil, aber es funktioniert gut für mich und hat bis jetzt keinen Unterschied gemacht.

Was ist der beste Weg, dies in Delphi so umzuschreiben, dass es sowohl einfach, verständlich als auch schnell ist?

(Als Referenz verwende ich Delphi 2009 mit Unicode-Strings.)

Folge:

Toby empfohlen Ich verwende einfach das If Then Else-Konstrukt. Wenn ich auf meine Beispiele zurückblicke, die eine CASE-Anweisung verwendeten, kann ich sehen, wie das eine brauchbare Antwort ist. Leider hat meine Aufnahme des CASE versehentlich meine eigentliche Frage verdeckt.

Es ist mir eigentlich egal, welches Stichwort es ist. Das ist nur ein Bonus, wenn die bestimmte Methode es wie die POS-Methode identifizieren kann. Was ich brauche, ist zu wissen, ob das Schlüsselwort in der Menge der Schlüsselwörter ist oder nicht.

Ich möchte also wirklich wissen, ob es etwas Besseres gibt als:

%Vor%

Das If Then Else-Äquivalent scheint in diesem Fall nicht besser zu sein:

%Vor%

In Barrys Kommentar zu Kornels Frage erwähnt er das TDictionary Generic. Ich habe die neuen Generic-Kollektionen noch nicht gelesen und es sieht so aus, als ob ich mich in sie vertiefen sollte. Meine Frage hier wäre, ob sie für die Effizienz gebaut werden und wie würde die Verwendung von TDictionary in Aussehen und Geschwindigkeit zu den obigen zwei Zeilen vergleichen?

Beim späteren Profiling habe ich festgestellt, dass die Verkettung von Strings wie in: ('' + MyKeyword + '') zeitlich gesehen sehr teuer ist und wenn immer möglich vermieden werden sollte. Fast jede andere Lösung ist besser als das.

    
lkessler 23.01.2010, 23:54
quelle

8 Antworten

3

Meistens verwende ich die IndexText-Funktion von StrUtils für diesen Zweck. Es ist ähnlich wie Ihre Pos-Methode, aber der Rückgabewert ist unabhängig von der individuellen Länge der Strings. Als Gimmick ist es auch Groß-und Kleinschreibung (verwenden Sie IndexStr, wenn Sie dies nicht wollen).

%Vor%

Der Kommentar zu diesen Funktionen erwähnt tatsächlich das Fallkonstrukt:

  

{AnsiMatchText & amp; AnsiIndexText   bieten eine ähnliche Funktion für den Handel   mit Zeichenfolgen}

    
Uwe Raabe 24.01.2010, 10:25
quelle
6
%Vor%

Im Allgemeinen verwenden Sie keine Zeichenfolgen als "Schlüssel", verwenden Sie Aufzählungen - sie sind sicherer und Sie erhalten viel von einer Geschwindigkeitserhöhung.

Leider hat Delphi (soweit ich weiß) keine Standard-Hashtable-Implementierung, die leicht zu benutzen wäre, Sie können jedoch immer Ihre eigenen zusammenstellen.

Übrigens klingt code for SEX viel lustiger als "wird für Bier kodieren": P

    
Kornel Kisielewicz 24.01.2010 00:26
quelle
5

Sie können eine const-Tabelle (die alphasortiert sein muss) und eine schnelle binäre Sortierung verwenden. Es ist sehr effizient und erfordert kein Hashing.

Hier ist die zu verwendende Funktion:

%Vor%

Und hier einige Beispiele für Schlüsselwörter:

%Vor%

Und es ist sehr einfach zu bedienen:

%Vor%

Sie können die Funktion IsKeyWord () einfach ändern, um den Index des Tokens zurückzugeben, wenn Sie es benötigen.

%Vor%     
Arnaud Bouchez 24.01.2010 11:17
quelle
3

Ihre Reihe von if -Anweisungen, um zu überprüfen, ob die Eingabe eines der angegebenen Schlüsselwörter ist, könnte verkürzt werden, indem einzelne Zeichen geprüft werden, um so schnell wie möglich zu retten. Dein Beispiel

%Vor%

könnte durch

ersetzt werden %Vor%

Bei case-insensitiven Schlüsselwörtern würde die case nach Groß- und Kleinschreibung suchen und der Vergleich würde AnsiCompareText() verwenden. Wenn Sie mehrere Keywords mit demselben Anfangsbuchstaben haben, könnten Sie diese case -Anweisungen verschachteln, aber die Lesbarkeit würde wahrscheinlich bald für sehr wenig Geschwindigkeitsgewinn leiden.

Wenn Sie das Maximum verwenden, können Sie eine Zustandsmaschine implementieren, die PChar verwendet, um den nächsten Zustand zu berechnen, der in den Fall else verzweigt, sobald das erste nicht übereinstimmende Zeichen gefunden wird. Es wäre schneller als jede Lösung mit Hashes.

    
mghie 24.01.2010 09:56
quelle
2

Ich denke das

%Vor%

ist bei weitem die beste Lösung. Ihre eigene Lösung ist sehr unelegant und für die minimale Verbesserung der Effizienz lohnt es sich nicht. Das Wenn-Dann-Konstrukt ist perfekt für das, was Sie wollen.

    
Toby Allen 24.01.2010 00:27
quelle
2

Für saubersten Code ist es am besten, Groß- und Kleinschreibung mit Aufzählungen zu verwenden, oder, wenn, wie von anderen vorgeschlagen, mit Zeichenketten abzuspeichern. Es gibt ein paar Lösungen abseits der ausgetretenen Pfade, wenn Sie wirklich dorthin wollen.

Eine besteht darin, eine String-Hash-Map zu verwenden, die wie eine Liste aussieht, die von Strings "indexiert" wird. Werte in der Liste wären Prozedurzeiger auf den Code, den Sie für jede Zeichenfolge ausführen möchten. Alle Prozeduren müssen die gleichen genauen Parameter haben - und Sie müssten die Hash-Karte selbst schreiben oder eine finden, die Sie z.B. in JVCL.

%Vor%

Zwei, und das ist etwas Seltsames, das ich einmal ausprobiert habe: Wenn und nur wenn Ihre Bezeichnerfolgen in 4 Zeichen passen (wie in allen Beispielen) und sie sind ansi-Zeichenfolgen (nicht Unicode-Zeichenfolgen), können Sie zuordnen Strings zu ganzen Zahlen direkt. Eine 32-Bit-Ganzzahl entspricht der Größe einer 4-Byte-Zeichenfolge. Sie können also Folgendes tun:

%Vor%

Jeder Zeichenfolgenbezeichner, der kürzer als 4 Zeichen ist, müsste mit Leerzeichen aufgefüllt werden, und bei den Zeichenfolgen wird zwischen Groß- und Kleinschreibung unterschieden ("chil" und "CHIL" ergeben unterschiedliche Werte). Um dies mit einer case-Anweisung zu verwenden, müssen Sie die Werte vorberechnen, die für Ihren Zweck geeignet sind oder nicht:

%Vor%

Und schließlich können Sie Ihre Fallaussage haben:

%Vor%

Dies ist ein spezieller Pflegecode, der nur dann einen Unterschied machen kann, wenn Sie Hunderte oder mehr Ihrer Bezeichner-Strings haben - das sollte eigentlich gar nicht passieren :) Es ist sicherlich leicht zu knacken. Ich stimme jedoch zu, dass Fallberichte besser sind als endlose Prozessionen von ... anderen ... Blöcken.

    
Marek Jedliński 24.01.2010 02:13
quelle
1

Haftungsausschluss: Die Antwort basiert auf der aktualisierten Problembeschreibung, d. h. einfach prüfen, ob eine Zeichenfolge übereinstimmt oder nicht.

Wenn Sie wirklich das letzte bisschen Leistung anstreben, könnten Ihnen einige zusätzliche Informationen über Ihre Daten helfen.

  • Wie viele Keywords sprechen wir? (welche Größenordnung)
  • ist der Satz von Keywords behoben?
  • gibt es eine Menge Wiederholungen in der Eingabe? (d. h. die gleichen X Schlüsselwörter wiederholen sich oft)
  • Wie ist das erwartete Treffer / Fehlverhältnis? Erwarten Sie, dass für 1000 eingegebene Wörter ein Schlüsselwort gefunden wird, oder erwarten Sie, dass fast jedes Wort gefunden wird?

Zum Beispiel

  • Für eine kleine Anzahl von Schlüsselwörtern (sagen wir etwa 20, abhängig von der Implementierung) wird der Overhead des Hashing wichtig.
  • Wenn Sie ein perfektes Hashing-Schema erhalten, können Sie es bekommen (siehe hier für ein Beispiel in C) kann jede Verkettung oder ähnliches Schema loswerden und einige wichtige Zyklen abschneiden. Dies wiederum würde voraussetzen, dass sowohl Ihre Keywords als auch Ihre Eingabe vorab bekannt sind, was nicht sehr wahrscheinlich ist.
  • Wenn es eine Menge Wiederholungen in den Schlüsselwörtern gibt (und eine große Hash-Sammlung, gegen die es zutreffen soll), könnte ein kleiner lokaler Cache der letzten X Wörter helfen.
  • wenn Sie viele eklatante Fehler erwarten (oder Ihr Hash-Algorithmus ist sehr ineffizient; P) könnte ein Trie effizienter sein als eine Hash-Tabelle.

Die meisten davon sind jedoch für gewöhnliche Performance-Tuning-Aufgaben etwas extrem. Ich würde wahrscheinlich standardmäßige "hashed set" -Implementierungen (Delphi-Generics, jcl, etc.) zuerst profilieren, um zu sehen, welche am besten in Ihrem Problemsatz funktioniert.

    
Paul-Jan 24.01.2010 08:35
quelle
0

Sie könnten auch zu einem eher objektorientierten Ansatz wechseln und etwas wie

haben %Vor%

und lassen Sie eine Fabrik die Befehle für Sie erstellen

%Vor%

Der aufrufende Code würde dann so einfach aussehen wie:

%Vor%

Auf diese Weise haben Sie alle Schlüsselwortzeichenfolgen in einer einfachen Factory-Klasse lokalisiert und eingekapselt, was spätere Änderungen an der Eingabesprache sehr einfach macht. Die Verwendung dieses befehlsbasierten Ansatzes hat weitere Vorteile, wie beispielsweise einfache Erweiterbarkeit.

Ich weiß, dass dies vielleicht nicht als Antwort auf Ihre Frage interpretiert wird, weil es nicht darum geht, wie schnell Sie es tun können. Aber es ist ein anderer Ansatz, über den es sich zu überlegen lohnt.

    
jpfollenius 24.01.2010 09:25
quelle