![]() |
Variable mit mehreren Werten vergleichen ohne "OR"
Guten morgen.
Delphi-Quellcode:
kann man das einfacher machen das ich einfach auf OR verzichente kann ? MFG
Procedure Gegenstand(Bezeichnung:String);
begin ... IF (Bezeichnung= 'rohr') or (Bezeichnung= 'schraube') or (Bezeichnung= 'schraubendreher') Then .... ... end; |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
ich sehe da keine andere "schöne" Lösung.
Dies hier geht nicht, weil String keine ordinaler Typ ist:
Delphi-Quellcode:
was Du noch machen kannst: mehrere if verschachteln
if x in ['aaa', 'bbb', 'ccc'] then
begin ... end;
Delphi-Quellcode:
was besseres fällt mir nicht dazu ein.
if x = 'aaa' then
begin if x = 'bbb' then begin if x = 'ccc' then begin ... end; end; end; |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Dann ist ja die erste Lösung (meine) schöner ;)
Denn wenn es um 10 vergleichweten kommen soll, dann werden das 10x or´s :( |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Das verschachteln wäre nicht der Nachbei mit "or" sonder das was der compiler intern bei "and" macht.
|
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Hallo,
bei 10 Vergleichswerten ist folgende Lösung wahrscheinlich übersichtlicher und flexibler:
Delphi-Quellcode:
Gruß, Volker
Procedure Gegenstand(Bezeichnung:String);
var sl : TStringList; begin sl := TStringList.Create; sl.CaseSensitive := true; sl.DelimitedText := 'rohr, schraube, schraubendreher'; IF sl.IndexOf(Bezeichnung) > -1 then ShowMessage(Bezeichnung + ' ist enthalten.'); sl.Free; end; |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
also bevor du mit der langsammen TStringList arbeitest dann besser so:
Delphi-Quellcode:
Ist auch nicht sonderlich effizient, da Pos() benutzt wird, drüfte aber schneller sein als eine Schleife, TStringList oä.
if Pos('-' + Bezeichnung + '-', '-rohr-schraube-schraubendreher-') > 0 then
Falls Pos() intern nach dem Boyer-Moore Algo. arbeitet ist die Stringsuche sogar sehr effizient. Die schnellste Lösung dürfte ein Tree sein. In einem solchen Baum sind deine Suchwörter auf spezielle Weise gespeichert so das man darin sehr sehr schnell überprüfen kann ob ein gesuchtes Wort existiert. Je nach Baum-Typus und Codierung würde dieser sogar weniger Speicherplatz verwenden als die Strings wie in deinem Beispiel zu speichern. ZB. Schraube und Schraubedreher würde nur einmal Schraube und einmal "dreher" im Tree speichern. Eine sehr effiziente Tree Struktur im Source kannst du hier saugen: ![]() Das ist ein DAWG und so könntest du ihn benutzen:
Delphi-Quellcode:
Gruß Hagen
var
List: TDawg = nil; procedure InitList; begin List := TDawg.Create; List.Insert('Schraube'#0'Schraubendreher'#0'Rohr'); List.Pack; end; procedure Search; begin if List.Exists(Suchstring) then end; |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Wie wäre es wenn Du die einzelnen Worte an ein Array übergibst, und dann per Schleife prüfst ob es existiert.
|
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
|
Re: Variable mit mehreren Werten vergleichen ohne "OR&q
Hi,
das hier sieht warscheinlich ein bischen blöd aus, funktioniert aber ;-)
Delphi-Quellcode:
Das folgende ist etwas eleganter ;-)
Procedure Gegenstand(Bezeichnung:String);
begin ... // statt '#' kann natürlich auch alles andere genommen werden ;-) if pos('#'+Bezeichnung+'#', '#rohr#schraube#schraubendreher#')>0 then .... ... // oder auch: 1 6 15 case pos('#'+Bezeichnung+'#', '#rohr#schraube#schraubendreher#') of 1: machwas; // rohr 6: machwas; // schraube 15: machwas; // schraubendreher else machwas; // nix end; ... end;
Delphi-Quellcode:
mfg
function getArrayIndex(s: string; a: array of string): integer;
var i: Integer; begin Result := -1; for i := low(a) to high(a) do begin if s = a[i] then begin Result := i; exit; end; end; end; procedure TestIt(Bezeichnung:String);; begin ... if getArrayIndex(Bezeichnung, ['rohr', 'schraube', 'schraubendreher']) > -1 then ... case getArrayIndex(Bezeichnung, ['rohr', 'schraube', 'schraubendreher']) of 0: machwas; // 1. String (rohr) 1: machwas; // 2. String (schraube) 2: machwas; // 3. String (schraubendreher) -1: machwas; // nicht gefunden end; ... end; MaBuSE |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
|
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Wie wäre es, wenn du die Strings in einem TStringHash verwaltest und dann nur noch innerhalb des Hashes suchst?
Guck dir mal folgendes an. ![]() |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
@Mabuse:
Delphi-Quellcode:
ja könnte man, zb.
// statt '#' kann natürlich auch alles andere genommen werden ;-)
if pos('#'+Bezeichnung+'#', '#rohr#schraube#schraubendreher#')>0 then ....
Delphi-Quellcode:
ups das hatte ich doch schon 4 Threads vorher gepostet ;)
if pos('-' + Bezeichnung + '-', '-rohr-schraube-schraubendreher-')>0 then ....
[edit] Mist, hat Mabuse auch schon erkannt. Liest überhaupt einer die blöde rote Box bevor man postet, ich nicht ;) [/edit] Die beste Lösung ist die 2. von Mabuse, aus Sicht des besten Codes, allerdings mit kleinen Änderungen:
Delphi-Quellcode:
1.) const Parameter machen die Sache effizienter vom erzeugten Code. Besonders beim const List: array of String ist das enorm wichtig. Denn nun wird unser Array[] im Source das wir übergeben -> ['rohr', 'schraube', 'schraubendreher'] durch den Compiler hardcoded als fertiges Array[] im Code abgelegt. Also auch wenn man vermuten würde das zur Laufzeit unser dynamisches Array[] erst erzeugt wird und die 3 Strings darin eingefügt werden, so passiert eben dies nicht. Aber nur wenn wir konstante Arrays[] benutzen. Denn wenn nicht so wird die Funktion IndexOf() uU. eine komplette Kopie des übergebenen Atrrays anlegen.
function IndexOf(const Value: String; const List: array of String): Integer;
var I: Integer; begin Result := -1; for I := Low(List) to High(List) do if Value = List[I] then begin Result := I; Break; end; end; procedure TestIt(Bezeichnung: String); begin case IndexOf(Bezeichnung, ['rohr', 'schraube', 'schraubendreher']) of 0: machwas; // 1. String (rohr) 1: machwas; // 2. String (schraube) 2: machwas; // 3. String (schraubendreher) -1: machnichts; // nicht gefunden end; end; 2.) du musst nicht zweimal in der Liste Suchen, ein case of reicht aus, also ohne if then vorher. Gruß Hagen |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Hallo. Sehr viele Lösungsansätze. Sehr gut!
Wie kann ich erfahren wie schnell jeder einzelne Lösung ist? Sind das "gewaltige" unterschiede? Oder minimale? das z.B. verwende ich sehr oft in meine Anwendung:
Delphi-Quellcode:
Wenn ich ein Eintrag in COMBOX Selektiren möchte.. Somit würde ja diese Funktion hervoragend passen (bessere Lesbarkeit, da ich solchen code (Struktur) sehr oft angewendet habe. Aber ist das SEHR langsam? Wie kann ich das in Zukunft selber "spüren" ? bei 1000 Einträgen?
Procedure Gegenstand(Bezeichnung:String);
var sl : TStringList; begin sl := TStringList.Create; sl.CaseSensitive := true; sl.DelimitedText := 'rohr, schraube, schraubendreher'; IF sl.IndexOf(Bezeichnung) > -1 then ShowMessage(Bezeichnung + ' ist enthalten.'); sl.Free; end; |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
1.) TStringList 2.) IndexOf() ohne binärer Suche 3.) Pos() 4.) BoyerMoorePos() 5.) IndexOf() aber mit binärer Suche, statt wie oben einfach linear 6.) Trees wie mein DAWG 7.) Hash-Vergleich Noch ein par Bemerkungen: 7.) Hash-Vergleich meint KEINE Hash-StringListe oder so ein Quatsch. Man sucht eine geeignetes Prüfsummenverfahren das für alle zu suchenden String in der Liste eine eindeutige Zahl liefert, zb. eine 32Bit Zahl. Diese Zahlen erzeugt man einmalig und kann dann so sehr sehr effizient vergleichen
Delphi-Quellcode:
Dh. in dieser Methode wird nur ein String real bearbeitet, nämlich der Suchstring Bezeichnung wir byteweise durch Prüfsumme umgewandelt. Danach gibnt es KEINE weiteren realen Stringvergleiche mehr.
case Pruefsumme(Bezeichnung) of
$12345678: ; $AB450CDE: ; $DFFFFF12: ; // usw. usf. end; Eine Hash-Liste empfehle ich niemals, da diese immer nur auf bestimmte Probleme bezogen ihren Aufwand lohnen. Trees benötigen fast immer mehr Speicher sind aber abgesehen von obiger Prüpfsummen-Methode die schnellste Lösung. Pos() ist schnell implementiert aber schlecht zu warten und nicht sonderlich schnell. Aber weitaus sachneller als eine TStringList jedesmal zu erzeugen, dann mit dem langsammen CommaText oä. die Liste zuzuweisen, dann vielleicht noch sortieren und dann erst darin suchen, und dann die Liste wieder freigeben. Uff, schon beim Schreiben dieses Satzes wird mir schlecht. Die Beste Lösung bei nur wenigen Strings in der Liste dürfte die 2. von Mabuse sein -> IndexOf() habe ich si mal genannt. Hier erzeugt der Compiler schonmal eine schöne hardcoded Datenstruktur aller Strings im Codesegement. Also keinerlei Allokationen oder Deallokationen dieser "Liste" mehr notwendig. Sortiert man diese Strings noch von Hand und benutzt in IndexOf() eine binäre Suche so ergibt sich ein ziemlich effizientes Verfahren das auch bei zb. 1024 Strings nur 11 Vergleiche benötigt. Aber es würden eben noch 11 * 2 Stringzugriff für diese Vergleiche notwendig sein, bei der TStringList wären dies ca. 512 pro Suche. Bei den Hash-Prüfsummen würde man denoch nur 1 String umwandeln in einen 32Bit Wert und diesen dann vergleichen in der CASE OF Abfrage, würde ja bei den anderen Verfahren ebenfalls notwendig sein. Das Problem bei der Hash-Prüfsummen-Methode ist es das man erstmal eine geeignete Funktion finden muß die bei allen Strings eine wirklich eindeutige Prüfsumme erzeugt. Wenn man davon ausgehen kann das der Wert in Bezeichnung nur aus Werten bestehen kann die in der zu suchenden Liste vorkommen dann ist das noch effizient möglich, sonst aber nicht. Wie gesagt: am elegantesten ist die const Array[] Methode, rein schon vom sauberen Eindruck den der Source macht und von der sich ergebenden Performance ist sie ein supere Kompromiss. Um längen besser als diese elende TStringList Rechnereien. (hab den Eindruck das es ausreichend ist einem Delphicoder die TStringList zu erklären, mehr benötigt er nicht ;) ) Gruß Hagen |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
Aber ich ärgere mich dann immer über mich selbst, da es zeigt, wie langsam man doch antwortet. (Inkl. Delphi Start, e-Mail lesen, ...) Zitat:
Zitat:
Da Karstdt im 1. Post ein if in seinem Code hatte, ich aber die case Variante zeigen wollte ;-) |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
Also: bei kleinen Listen mit > 3 aber oft < 32 Einträgen ist die Array[] Methode die eleganteste und stellt den besten Kompromiss dar. Wenn man jetzt noch die IndexOf() Funktion um drei Features erweiteren würde 1.) Suche mit und ohne Berücksichtigung der Groß/Kleinschreibung 2.) Suche per Binärer Suche 3.) Partielle Suche, dh. der erste Eintrag der die längste Übereinstimmung mit dem Suchmuster hat wird gefunden, statt keinem Resultat. dann wäre sie ein idealer Beitrag für die CodeLib. Gruß hagen |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
Wenn der Vergleich (case) im Programm häufig vorkommt (z.B. in einer Schleife), könnte man ja statt dem Case ein array of procedure verwenden, das zuvor initialisiert wurde. Das müsste doch funktionieren, oder?
Delphi-Quellcode:
var
i: Integer; machWas: array of procedure; ... begin ... while (...) do begin ... i := IndexOf(s, [...]); // [...] -> viele Einträge if i>-1 then machWas[i] else machNix; ... |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
Jetzt nur noch die Frage ist es schnell? Ich glaube schneller als ein Case schon (ohne Init)
Delphi-Quellcode:
(Mit procedure of object könnte man natürlich auch Methoden in das Array legen ;-))
var
i: Integer; machWas: array of procedure; ... procedure rohr; ... procedure schraube; ... procedure schraubendreher; ... begin // ein mal init SetLength(machWas, 3) machwas[0] := rohr; machwas[1] := schraube; machwas[2] := schraubendreher; ... while (...) do begin ... // vielfacher Aufruf (z.B. in Schleife) i := IndexOf(s, ['rohr', 'schraube', 'schraubendreher']); if i>-1 then machWas[i] else machNix; ... |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Hallo MaBuSE,
hier eine Erweiterung deiner Idee:
Delphi-Quellcode:
Gruß Hawkeye
// uses StrUtils (AnsiIndexText)
procedure MachNix; begin end; procedure rohr; begin end; procedure schraube; begin end; procedure schraubendreher; begin end; const JumpTable: array [-1..2] of procedure = (MachNix, rohr, schraube, schraubendreher); var s : string; i : Integer; begin s := 'ScHrAuBe'; i := AnsiIndexText(s, ['rohr', 'schraube', 'schraubendreher']); JumpTable[i]; end; |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Delphi-Quellcode:
und ja ist sehr schnell da nur ein Lookup in einer festen Tabelle entsteht und dann ein call ausgeführt wird. Schneller als jede CASE OF Abfrage.
JumpTable[AnsiIndexText(s, ['rohr', 'schraube', 'schraubendreher'])];
AnsiIndexText() kannte ich noch garnicht, in D5 gibts die noch nicht. Hast du mal in die Implementierung geschaut wie Borland die Suche implementiert hat ? Jetzt müsste man noch eine Funktion schreiben die den CALL der durch den Compiler erzeugt wird ersetzt durch einen CALL zu einer nested Procedure. Dadurch ist es möglich die Procedures lokal und nested zu codieren und innerhalb dieser Procedures kann man auf den übergeordneten Stack zugreifen. Also wie gewohnt bei nested Funktionen. Das macht dann den Source noch übersichtlicher. Gruß Hagen |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Zitat:
AnsiIdentText kannte ich auch noch nicht. Man lernt ja nie aus. Die Funktion gibts schon in D7 und sieht wie folgt aus:
Delphi-Quellcode:
Das ist also fast das gleiche wie unser Beispiel. :mrgreen:
{ *********************************************************************** }
{ Delphi Runtime Library } { Copyright (c) 1995-2001 Borland Software Corporation } { *********************************************************************** } unit StrUtils; ... function AnsiIndexText(const AText: string; const AValues: array of string): Integer; var I: Integer; begin Result := -1; for I := Low(AValues) to High(AValues) do if AnsiSameText(AText, AValues[I]) then begin Result := I; Break; end; end; ... In der AnsiSameText wird schliesslich noch eine Weitere Funktion aufgerufen, die dann noch eine aufruft und diese ruft dann folgende Win API auf:
Delphi-Quellcode:
Die im Grunde aber auch nur ein aText = aValues[I] macht ;-)
function CompareString; external kernel32 name 'CompareStringA';
In eigener Sache (Zitat aus Borland VCL / RTL) Anmerkung zum Zitat: Die Verwendung von Zitaten ist durch das Urheberrecht geregelt und unter bestimmten Voraussetzungen gestattet, ohne dass eine Erlaubnis des Urhebers eingeholt oder diesem eine Vergütung gezahlt werden müsste (§ 51 UrhG in Deutschland) Es handelt sich hier um ein Kleinzitat. Kleinzitate dürfen weiterreichend verwendet werden. Der Zitierzweck muss erkennbar sein. Das Zitat muss also in irgendeiner Beziehung zu der eigenen Leistung stehen, beispielsweise als Erörterungsgrundlage. Der Umfang des Zitats muss dem Zweck angemessen sein. (frei zitiert aus Wikipedia: ![]() |
Re: Variable mit mehreren Werten vergleichen ohne "OR&a
Naja letzten Endes muss man ja den String vergleichen (wenn man nicht hashed).
Aber er spart sich die ganzen Jumps, sehr elegant, find das auf irgend eine komplizierte Sichtweise schön :) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:11 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 by Thomas Breitkreuz