![]() |
Datenbank: Access • Zugriff über: ADO
Datensätze zufällig anzeigen, aber alle nur einmal
hallo,
ich habe eine Datenbank in der Datensätze drin sind. Dann habe ich ein Programm, dort mache ich eine Adoquery und frage bestimmte Datensätze ab. Nun habe ich als ergebnis von RecordCount z.B. 10 Datensätze. Diese sollen nun nacheinander in zufälliger Reihenfolge in meinem Programm angezeigt werden. Mein Problem ist nun, wie ich dies hinkriege. Was ich bisher habe ist, dass ich im OnCreate-Ereignis Randomize aufrufe und später in meinem Programm, wenn ich meine adoquery ausgeführt habe und die Datensätze anzeigen will dieses:
Delphi-Quellcode:
Ich hoffe, mir kann da jemand weiterhelfen, oder hat einen besseren vorschlag, wie ich das Problem lösen kann. Ich probiere ich schon den halben Tag daran rum und krieg es nicht gebacken
z:= RandomRange(1, adoquery1.RecordCount);
//nun müsste ich auf den z. Datensatz zugreifen und diesen anzeigen //kann ich dann diesen Datensatz aus der Query rausschmeissen, ohne dass er in der //DB rausgeschmissen wird? //so müsste ich doch erreichen, dass jeder Datensatz dann nur einmal angezeigt wird |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Hai Susanne,
der einzige Weg der mir einfällt ist der über .RecNo die Datensätze in einer zufälligen Reihenfolge anzusprechen. Du müsstest also deine Record-Nummern (die ja nur eine zusammenhängende Liste von Integern sind) in eine zufällige Reihenfolge bringen. Dafür kannst Du z.B. diesen ![]() Dann kannst Du so die Datensätze in einer zufälligen Reihenfolge ansprechen.
Delphi-Quellcode:
Ich habe den Code von Hagen gewählt weil Du dann ganz einfach auch sagen kannst: "Ich möchte von meinen 10 Datensätzen 5 Stück in einer zufälligen Reihenfolge haben).
procedure TForm1.Button1Click(Sender: TObject);
var Sortiert, Zufall: TZahlen; anzahl : Integer; ndx: Integer; begin anzahl := Query1.RecordCount; Lotto(Sortiert, Zufall, anzahl, anzahl); for ndx := 0 to High(Zufall) do begin Query1.RecNo := Zufall[ndx]; // Mache etwas mit dem aktuellen // Datensatz end; end; |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Da man X aus X Records zufällig sortiert haben möchte ist mein Code eine relativ ineffiziente Lösung. Es geht besser.
Delphi-Quellcode:
Probiere obigen Code einfach aus und analysiere ihn, ich glaube das ist einfacher als ihn jetzt hier umständlich erklären zu müssen. Die Schleifen laufen zwar mit RecordCount^2 Komplexität, allerdings werden nur RecordCount Datensatzzugriffe ausgeführt. Da die Laufzeitgeschwindigkeit der Random() Funktion vernachlässigenbar ist, stellt das kein Peformanceproblem dar. Vorteil ist das man ohne Speichertabellen, Sortierungen etc. auskommt.procedure ListeRecords: var Seed,I: Integer; begin Seed := RandSeed; // Zufallsstartwert speichern for J := 0 to RecordCount -1 do begin RandSeed = Seed; for I := 0 to RecordCount -1 do if Random(RecordCount) = J then PrintRecord(I); end; end; Gruß Hagen |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Zitat:
darum habe ich ja in meinem Abschlusssatz geschrieben das ich deinen Code vorschlage weil man dann auch, ohne Änderung des Codes, nur x aus y Records zufällig anzeigen kann ;-) Oder habe ich deinen Code aus dem Lotto Thread da falsch verstanden? |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Nein hast du nicht :-)
Und wenn man es so will bin ich exakt deiner Meinung, mein Lottocode wäre die beste und effizienteste mir bekannte Alternative, ausgenommen eben mein obiger Vorschlag, denn auch dieser kann X aus Y Records aussortieren. Dazu wird einfach die äussere Schleife verkürzt. Es hängt nun nur von der Geschwindigkeit der Funktion Random() ab ob man obigen Source oder meinen Lottocode benutzen sollte. Obiger Code hat noch einen klitzekleinen Vorteil: man kann auch ohne Kenntnis der Recordnummer die Records aussortieren. Die innere Schleife I geht dann einfach per DataSet.Next über die Datenbank durch. Gruß Hagen |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Das ist zuerst ein kombinatorisches Problem. Letztlich die Umkehrung der Sortierung.
Die einfachste Methode ist daher eine Liste der RecNo's zu erstellen und sie zu verwuerfeln. 10 x Anzahl der Datensaetze je zwei zufaellig gewaehlte Elemente der Liste zu tauschen sollte mehr als ausreichend sein. Danach die Liste von vorn nach hinten abarbeiten. Das ist nur problematisch wenn die Liste sehr lang ist. |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
@Robert,
nun schaue dir mal meinen Lottocode genauer an, er vermeidet nämlich diese Methode und benötigt nur eine Liste von X Elementen wenn man X aus Y Records benötigt. Desweiteren ist mein obiger Vorschlag eine Lösung die ohne diese Liste auskommt. Beide Vorschläge, der Lottocode und der obige Vorschlag, lösen exakt dieses kombinatorische Problem das du ansprichst. Aber eben ohne deine programmtechnische Lösung des Problemes und sie sind, einmal verstanden, auch die einfachste Lösung :-) Übrigens fällt mir da noch ein Vorteil zum obigen Code ein. Er kann die Records partitioniert ausgeben. D.h. die Schlefe J kann durch aus auch von X nach Y laufen, wobei X > 0 und Y < Recordcount ist. Man kann so also Häppchenweise aus einem Set von Datensätzen nacheinander Blöcke anzeigen, ohne Wiederholungen zu bekommen. Gruß Hagen |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Ich wollte es ja nicht richtig loesen sondern einfach :-)
Die Originalfrage will ja nur alle Datensaetze anzeigen, keine Auswahl daraus. Im uebrigen ist es immer interessant zu erwaehnen das es eine Umkehrung von Sortieren gibt. |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
@Robert, ich weis worauf du hinaus wolltest, ich behaupte aber das es eben nicht die einfachste Lösung ist. Es ist in fakt die intuitivste Lösung, aber nicht die einfachste :-)
Gruß Hagen |
Re: Datensätze zufällig anzeigen, aber alle nur einmal
Delphi-Quellcode:
function RandomUnique(Index,Count: Integer; Order: Integer = $12345678): Integer;
var Seed,I,J: Integer; begin Seed := RandSeed; try for I := 0 to Count -1 do begin RandSeed := Order; for J := 0 to Count -1 do if Random(Count) = I then if Index = 0 then begin Result := J; Exit; end else Dec(Index); end; Result := 0; // dieser Fall kann eigentlich nie eintreten finally RandSeed := Seed; end; end; Obige Funktion kannst du so einsetzen wie gewünscht:
Delphi-Quellcode:
Der Parameter "Order" stellt dabei sowas wie eine eindeutige Nummer zur Reihenfolge der erzeugten Nummern dar. Er muss für jeden Aufruf der Funktion die zur gleichen Liste stammt auch immer gleich sein.ListOrder := Random(MaxInt); // 1. Datensatz DataSet.RecNo := RandomUnique(0, DataSet.RecordCount, ListOrder); // 2. Datensatz DataSet.RecNo := RandomUnique(1, DataSet.RecordCount, ListOrder); // 3. Datensatz DataSet.RecNo := RandomUnique(2, DataSet.RecordCount, ListOrder); Das Verfahren ansich ist echt simpel. Durch die Manpulation von RandSeed == Startwert des Zufallsgenerators erzeugt man zu jedem Zeitpunkt ausgehend von Order immer wieder die gleiche Liste von Zufallszahlen (dafür ist ja auch ein Pseudozufallsgenerator und RandSeed gedacht :-) ) Wir müssen also nun nur noch die "Filterung" für das auszuwählende Element der so produzierten Zufallszahlenliste vornehmen. Man muß halt Count^2 mal durch diese Liste durchgehen um eine Eindeutigkeit zu produzieren, da unsere Random() Funktion eben nicht eindeutige Nummern erzeugt. Nungut, obige Funktion sollte somit auch diese häufig gestellte Frage beantworten. Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:25 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-2025 by Thomas Breitkreuz