![]() |
Zahlen überprüfen --> keine darf doppelt
Hallo,
ich soll als Hausarbeit ein kleines Tool schreiben, welches Zahlen miteinander vergleicht. Ich habe 4 Edit Felder in den Zahlen von eins bis vier eingetragen werden sollen. Bsp.: 1 2 3 4 Es darf keine Zahl doppelt eingetragen werden. Also so nicht: 1 2 2 4 Also ähnlich wie bei Sudoku!!! Ich habe das Programm schon fertig. Es gibt nur ein Problem. Die Routine, die überprüft ob eine Zahl doppelt vorkommt, soll erweiterbar sein. Das heisst es kann passieren, dass mal 5 oder 6 Edit Felder hinzugefügt werden. Dann soll es mit so wenig aufwand wie möglich trotzdem Funktionieren. Und das ist mein Problem. Ich hatte das Problem folgendermäßen gelöst. Ich habe alle Permutionen von 1234 gebildet und in ein Array gespeichert. Dann habe ich die Eingabe des Benutzers mit dem Array verglichen. Wenn die Eingabe des Benutzers im Array vorhanden ist, dann ist die Eingabe richtig, sonst ist bei der Eingabe ein Fehler unterlaufen. Kann man das eigentlich so machen? Oder gibt es trotzdem eine Variante um an der überprüfung vorbei zu kommen? Weiss nicht!!! So, das funktioniert alles super. Ich kann es auch auf 10 und mehr Edit Felder erweitern, bloß die ganze Angelegenheit dauert ein weilchen. Hat ihr vieleicht einen Tipp für mich wie ich das ganze schneller machen kann??? MFG Christian18 |
Re: Zahlen überprüfen --> keine darf doppelt
ich würde die eingaben in ein array lesen. anschließend das array sortieren. und dann musst du nur noch überprüfen ob 2 mal die gleiche zahl hintereinander im array steht.
bsp: eingaben: 5, 6, 4, 6, 8 sortiert: 4, 5, 6, 6, 8 und wenn du dann an die dritte stelle kommst, merkst du ja, dass danach nochmal die gleiche zahl kommt. das ganze sollte dann nicht so lange dauern. |
Re: Zahlen überprüfen --> keine darf doppelt
Hallo,
ja stimmt. Dein Lösungsansatz ist auf jeden Fall effiktiver als meiner. Gibt es vieleicht noch effektivere Ansätze??? Freu mich schon auf die Antworten. [EDIT] Ich vermute mal das es irgendwann mal ein Sudoku Spiel werden soll. Denn warum die erweiterung ??? Macht für mich keinen Sinn!!! aber naja mal schauen was kommt. LG Chris |
Re: Zahlen überprüfen --> keine darf doppelt
Hum...
1.) Controls durchgehn 2.) Wenn Edit in Zahl umwandeln 3.) Zahl mit Array prüfen -> wenn nicht drin: reinschreiben -> wenn drin: Routine abbrechen evtl. Edit umfärben. |
Re: Zahlen überprüfen --> keine darf doppelt
Du benutzt ur sehr sehr wenig Zahlen -> 1 bis 4. Das lässt sich immer besser optimieren als zb. der Vorschlag die Zahlen in ein Array[] zu speichern, es zu sortieren und auf Duplikate zu prüfen. In deinem Falle ist dies nämlich sehr umständlich.
Baue dir ein Array[1..4] of Boolean. Initialisiere es mikt Fillchar(Array, SizeOf(Array), False), also alle Elemente = FALSE. Nachdem der Benutzer in einem Edit eine Zahl eingegeben hat, zb. im OnKeyPress(), wandelst du mit StrToInt(Edit.Text); dessen Zahl in einen Integer um. Dieser Wert wird als erstes überprüft auf >=1 und <=4, also StrToInt(Edit.Text) >= Low(Array) und <= High(Array). Danach benutzt du diesen Index ins Array und schaust nach ob dort TRUE oder FALSE steht. Bei TRUE hat schon ein anderes Edit die gleiche Zahl bei FALSE noch kein anderes Edit, ergo: das Array Elemlent auf TRRUE setzen. Lange Rede kurzer Source
Delphi-Quellcode:
Vorteile sind eben das es sehr einfach verständlich ist und aus Sicht der Performance wird es kein schnellers Verfahren geben in deinem Falle. Die Komplexität meines Vorschlages ist O(1) (Big O) und damit weitaus schneller als jeder Sortier- oder Suchalgorithmus.
type
TForm1 = class(TForm) private FZahlen: array[1..4] of Boolean; end; procedure TForm1.EditKeyPress(var Key: Char; ....) // alle deine Edits verweisen mit OnKeyPress() auf diesen Eventhandler var I: Integer; begin if Key in ['0'..'9'] then begin I := StrToInt(Key); if (I >= Low(FZahlen)) and (I <= High(FZahlen)) and not FZahlen[I] then FZahlen[I] := True else Key := #0; // lösche Taste, erscheint also nicht in Edit.Text end; end; procedure TForm1.ButtonRestartClick(); // lösche alle Edits und das FZahlen Array, Benutzer kann nun neu eingeben var I: Integer; begin FillChar(FZahlen, SizeOf(FZahlen), 0); for I := 0 to ControlCount -1 do if Controls[I] is TEdit then TEdit(Controls[I]).Text := ''; end; Man kann das so wie oben machen immer dann wenn man nur sehr kleine und wenige Zahlen überprüfen/sortieren muß. Gruß Hagen |
Re: Zahlen überprüfen --> keine darf doppelt
Hi
Denkbar wäre auch eine globale Stringvariable, die im OnKeypressed-Ereignis über Posnach der Zahl sucht und diese eventuell anhängt.
Delphi-Quellcode:
In der Reset- Routine reicht dann ein
if Pos(Key, Zahlenstring) =0 then ZahlenString:=ZahlenString+Key else Key:=#0;
Delphi-Quellcode:
ok, damit keine anderen Zeichen in den Zahlenstring kommen, die Abfrage ist bereits schon erklärt...
Zahlenstring:='';
Gruß oldmax |
Re: Zahlen überprüfen --> keine darf doppelt
Hi,
waere es in diesem Fall nicht schneller einen mit 0 initialisierten Bit Array zu haben? Dann koenntest Du der Reihe nach jeden Bit Array auf Eins setzen (00001000000...), dessen Index der Zahl entspricht. Davor kannst Du noch checken ob der schon eins hat oder nicht, also schon im String vorkommt. Sollte eigentlich sehr platzsparend, schnell und einfach zu erweitern sein! LG Niels |
Re: Zahlen überprüfen --> keine darf doppelt
hi
Also, alle Abfragen mit onkeypressed sind nur geeignet für Zahlen von 0 - 9, aber was ist mit 164555 ? dazu Zitat : Zitat:
in der OnExit -Methode prüft man
Delphi-Quellcode:
Soviel zur Erweiterbarkeit und unbekannten Grenzen......
If Pos(';'+Edit1.Text+';',Zahlenstring)=0 then ZahlenString:=Zahlenstring+Edit1.Text+';'
else Edit1.Text:=''; @niels Natürlich gibt's Arrays und in einem Array [0..9] of Boolean kann ich jede Zahl markieren. Schneller.. hmmm, bei Zahlen von 0 bis 9 vermutlich nur für den PC, nicht für den Anwender, denn der merkt den Unterschied zwischen 3ms und 30 wohl kaum, obwohl da Faktor 10 drin ist.... Aber gut, manchmal machts schon Sinn, Geschwindigkeitsoptimiert zu denken und zu programmieren. Gruß oldmax |
Re: Zahlen überprüfen --> keine darf doppelt
Es geht nicht darum "Geschwindigkeitsoptimiert" zu arbeiten, sondern um effektiv und effizient zu arbeiten. Entscheidend ist das der Programmierer hierbei die zu dem Problem optimal passende Lösung findet. Sie sollte schlicht sein und nach Möglichkeit annerkannte Standard-Algos. der Programmierung benutzen, wenn sie auch Sinn machen.
Beispiel eben 6 Zahlen zwischen 1 bis 6 auf Duplikate prüfen. Ein sehr einfaches Problem mag man meinen, aber an Hand der unterschiedlichen Lösungsansätze kann man sehr wohl erkennen wie der Wissenstand, bzw. die Fähigkeit des Programmieres ein Problem analytisch zerlegen zu können, gereift ist. Standdardlösung wäre es die Zahlen in ein Array/Liste zu packen, diese zu sortieren und vor dem Einfügen eines neuen Wertes per binärer Suche in dieser Liste den Wert zu überprüfen. Eine idelae Aufgabe für eine TIntegerList (TList Nachlkommen) die mit Duplicates=dupIgnore arbeitet. Aber in diesem Falle ist es auf Grund der geringen Zahlen/Menge offensichtlich das man eine viel simplere Lösung benutzten kann. Also einfach ein Array/Liste mit der maximalen Anzahl aller vorkommenden Zahlen initialisieren und dann einfach jede Zahl aus dem Array rausstreichen die eingegeben wurde. Da unsere jeweilige Zahl der direkte Index in dieses Array[] darstellt entfällt das Durchsuchen/Sortieren eines Speicherbereiches. Nun stellt sich die Frage welche Datentypen der Programmierer dafür wählt. Auch hier gibts essentiell zwei unterschiedliche Denkweisen: 1.) man nehme schon vorhandene Klassen/Code egal ob er überhaupt geeignet ist. Das sind Vorschläge wie "nim TList und caste alle deine Integer von/nach Pointer", oder "nimm einen String der erstmal leer ist, hänge die Zahlen als String hintendran und überprüfe mit Pos ob die neue Zahl vorkommt im String". 2.) man benutzt die Fähigkeit der Programmiersprache gezielt eigene Datentypen zu konstruieren, eben ein array[1...6] of Boolean. Der Unterschied in beiden Arbeitsstilen ist der das der eine immer nur das Problem zu lösen versucht indem er Standardgeschichten die schon fertig sind benutzt. Er passt quasi die Lösung des Problemes an die ihm zur Verfügung stehenden Mittel an. Benötigt man zur Lösung des Problemes einen Hammer und die Programmiersprache enthält keine vorgefertigte Klasse/Code "Hammer" dann wird ein solcher Programmierer es schwerer haben. Der andere baut sich eine eigene Umwelt in der er das jeweilige Problem optimal lösen kann, indem er der Programmiersprache sagt was er haben möchte als Umwelt. Man könnte sagen das dies den Unterschied zwischen einem Anwendungs- und Systementwickler ausmacht. Bei meinen Postings ging es also nicht darum das der erzeugte Code nun die gleiche Aufgabe in 3ms statt 30ms lösst, sondern darum aufzuzeigen das in diesem Falle auch eine ganz ganz simple Lösung optimal sein kann. Es ist klar das wenn sich die Aufgabenstellung verändert, zb. > 100 Zahlen und nicht nur einstellige Zahlen, sich auch die benutzte Lösung unterscheiden muß. Das was mich "wurmt" ist eher der Punkt das Vorschläge kamen die eher sehr unelegant sind, zb. mit Strings zu rechnen statt gezielt eigene Datentypen zu benutzen ! Das ist so als würde der Programmierer nur 50% der Leistungsfähigkeit seiner Programmiersprache benutzen, denn man programmiert nicht nur Klassen, Prozeduren und Formulare sondern meist als Schritt davor programmiert/deklariert man seine Datentypen zugeschnitten auf das Problem. Gruß Hagen |
Re: Zahlen überprüfen --> keine darf doppelt
Hallo,
ich hätte auch noch einen Lösungsansatz - ohne Anspruch auf Reife:
Delphi-Quellcode:
Freundliche Grüße
uses
StrUtils; type TNumberSet = set of 1..9; var NumberSet: TNumberSet; function CheckNumber(var ns: TNumberSet; n: Integer): Boolean; begin Result := True; if not (n in ns) then ns := ns + [n] else Result := False; end; procedure TDemoForm.ButtonClick(Sender: TObject); const FMT = '%d ist %s'; var i, n: Integer; b: Boolean; begin NumberSet := []; for i := 1 to 9 do begin n := Succ(Random(9)); b := CheckNumber(NumberSet, n); ShowMessage(Format(FMT, [n, IfThen(b, 'okay', 'doppelt')])); end; end; |
Re: Zahlen überprüfen --> keine darf doppelt
Mal mein Ansatz als Code:
Delphi-Quellcode:
Es geht die Edits unter einem Control durch, zählt TEdit-Ableger, und prüft gegen ein dynamisches Bool-Array.
function CheckDuplicates(ParentControl: TWinControl; var WrongEdit: TEdit): Boolean;
var i,n: Integer; ba: array of Boolean; begin Result := False; n := 0; // Edits zaehlen for i := 0 to Pred(ParentControl.ControlCount) do if ParentControl.Controls[i].InheritsFrom(TEdit) then Inc(n); // Keine Edits? Dann Ende. if n = 0 then exit; // ByteArray setzen SetLength(ba, n); // Edits checken for i := 0 to Pred(ParentControl.ControlCount) do if ParentControl.Controls[i].InheritsFrom(TEdit) then begin // Zahl auslesen, wenn keine Zahl dann 0, wenn 0 dann ignorieren n := StrToIntDef((ParentControl.Controls[i] as TEdit).Text, 0) - 1; if n >= 0 then begin // Mit Array vergleichen If ba[n] then begin WrongEdit := (ParentControl.Controls[i] as TEdit); Result := True; Exit; end else ba[n] := true; end; end; end; Trifft es auf ein Edit mit einer Zahl, die schon existiert, bricht es ab und notiert dieses Edit in WrongEdit. So kann man dieses selektieren, markieren, etc. Aufgerufen wereden könnt es etwa so:
Delphi-Quellcode:
Ein netter Nebeneffekt ist, dass es Zahlen, die grösser als die Anzahl der Edits sind ebenfalls als Doppelte angezeigt werden...
var
we: Tedit; begin if CheckDuplicates(Panel1, we) then begin // mach etwas mit we end; end; [edit] noch ein bissel Entbugged ;) [/edit] |
Re: Zahlen überprüfen --> keine darf doppelt
Hi wenn du das schon so machst dann kannst du auch gleich auf Duplikat prüfen ohne dein Array[] of Boolean
Delphi-Quellcode:
Gruß Hagen
function CheckDuplicates(const Edit: TEdit): Boolean;
var I: Integer; Zahl: String; begin Result := False; if Edit is TEdit then begin Zahl := AnsiUpperCase(FullTrim(Edit.Text)); with Edit.Parent do for I := 0 to ControlCount -1 do if (Controls[I] <> Edit) and (Controls[I] is TEdit) and AnsiCompareText(FullTrim(TEdit(Controls[I]).Text)), Zahl) = 0 then Exit; Result := True; end; end; procedure TForm1.EditChange(Sender: TObject); // alle TEdit.OnChange verweisen auf diesen Eventhandler begin if CheckDuplicates(Sender as TEdit) then with Sender as TEdit do raise Exception.CreateFmt('Der Wert %s aus %s kommt schon vor', [Text, Name]); end; |
Re: Zahlen überprüfen --> keine darf doppelt
Hm... ja, setzt aber voraus, dass man bei jedem Edit das event definiert...
Najo. Viele Wege führ'n nach Rom :mrgreen: |
Re: Zahlen überprüfen --> keine darf doppelt
Und? alle TEdits auf dem Form per STRG+Maus Taste markieren, in OnChange im OI dann auf TForm1.EditCHange() setzen.
Geht man diesen Weg nicht so muß man denoch irgendeinen Zeitpunkt, bei dem sich der Inhalt eines der TEdits verändert, aussuchen und dann die Funktion CheckDuplicates() per Hand im Source aufrufen. Na, da bevorzuge ich doch die Events im OI auf einen gemeinsammen Eventhandler zu setzen, das kostet dann keinerlei extra Quelltext. Gruß Hagen |
Re: Zahlen überprüfen --> keine darf doppelt
Ich sag doch gar nix dagegen, Hagen... :angel2:
Da ich nicht vor der Aufgabe stand und nur einen Lösungsansatz zeigen wollt, hab ich nur nicht weiter gedacht als nötig war :oops: |
Re: Zahlen überprüfen --> keine darf doppelt
Hi
@ Hagen Nun, nicht das ich dir auf die Füße treten will, aber manchmal irrt auch ein Fachmann. Zitat: Zitat:
Sorry, für mich sind die Inhalte eines Editfeldes immer noch Strings und daher ist ein Vergleich mit Strings durchaus etwas, was dich nicht wurmen sollte. Andererseits, mir ist's letztlich egal, ob's dich wurmt Gruß oldmax |
Re: Zahlen überprüfen --> keine darf doppelt
Hallo,
so denke ich auch. Warum neues (Datentyp) erfinden, wenn für die Aufgabe auch TStringList geht. mit Duplicates:= [dupError] und try except um das Insert bekommt man ganz schnell Dopplungen raus. Zu den Edits: Ich würde hier noch Tag benutzen, um die Zahlen-Edits von viell. vorhandenen anderen Edits zu unterscheiden,also etwa so
Delphi-Quellcode:
Heiko
for i:= 0 to Components.Count do
begin if Components[i] is TEdit then begin Edit:= TEdit(Components); if Edit.Tag=1 then begin // hier kommt jetzt das "versuche einzufügen" // das Edit kann z.B. benutzt werden, // um per Edit.Focus den falschen Eintrag zu markieren end; end; end; |
Re: Zahlen überprüfen --> keine darf doppelt
Ne Stringliste wäre auch mein Vorschlag gewesen, da man sich hier zudam das Konvertieren nach Integer spart.
Damit das mit den Duplicates auch funktioniert nuss man allerdings die Stringliste auch sorted=true setzen. Wenn man kein exception-handlig machen will, kann man die Liste auch auf dupIgnore stellen. Dann merkt man sich einfach vor dem Einfügen die Anzahl, fügt ein und wenn sich die Anzahl nicht erhöht hat, gabs die Zahl schonmal. Diese Lösung ist nicht nur elegant, sondern auch effektiv, da die Stringliste eine Binärsuche verwendet, sobald sie sortiert ist. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:30 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