Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Datensätze zufällig anzeigen, aber alle nur einmal (https://www.delphipraxis.net/43865-datensaetze-zufaellig-anzeigen-aber-alle-nur-einmal.html)

Susanne 9. Apr 2005 21:49

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:
   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
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

Sharky 10. Apr 2005 05:10

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 Code von Hagen aus dem Lotto-Thread verwenden.

Dann kannst Du so die Datensätze in einer zufälligen Reihenfolge ansprechen.
Delphi-Quellcode:
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;
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).

negaH 10. Apr 2005 11:32

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:

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;
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.

Gruß Hagen

Sharky 10. Apr 2005 11:37

Re: Datensätze zufällig anzeigen, aber alle nur einmal
 
Zitat:

Zitat von negaH
Da man X aus X Records zufällig sortiert haben möchte ist mein Code eine relativ ineffiziente Lösung....

Hai,

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?

negaH 10. Apr 2005 11:44

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

Robert Marquardt 10. Apr 2005 11:45

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.

negaH 10. Apr 2005 11:51

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

Robert Marquardt 10. Apr 2005 11:58

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.

negaH 10. Apr 2005 12:00

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

negaH 10. Apr 2005 12:56

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:

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);
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.

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.
Seite 1 von 2  1 2      

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