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.
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}
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
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% 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
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.
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.
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.
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.
Zum Beispiel
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.
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.
Tags und Links optimization delphi case-statement lookup