AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi "array-Einträge" nicht doppelt auslesen
Thema durchsuchen
Ansicht
Themen-Optionen

"array-Einträge" nicht doppelt auslesen

Ein Thema von schmitzlipp · begonnen am 23. Mai 2006 · letzter Beitrag vom 23. Mai 2006
Antwort Antwort
schmitzlipp

Registriert seit: 6. Nov 2005
9 Beiträge
 
#1

"array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 16:58
Ich soll als Schulprojekt ein kleines Quiz bauen.
Ich lese Frage und Antworten jeweils aus einer Zeile in einen array of string ein.

Delphi-Quellcode:
AssignFile(myFile,datei);
    Reset(myFile);
    while not Eof(myFile) do
    begin
      ReadLn(myFile, text[i]);
      inc(i);
    end;
closefile(myfile);
Dannach wird per random ein string aus diesem array "rausgefischt" den ich dann Zerlege.
Nach dem die Frage beantwortet wurde, wird wieder ein string zufällig ausgewählt.
Nun kann es aber passieren dass ein string doppelt ausgewählt wird, was ich aber unterbinden möchte,
da das quiz sonst witzlos wäre, wenn man zweimal die gleiche frage bekäme.
Nun bräuchte ich eine Lösung die solange string heraussucht (nicht doppelt, keine festgelegte reihenfolge), bis jeder string einmal dran war.
Ich hatte schon eine Idee:
Jedem string im array text eine zahl zu vergeben und diese dann in einem anderen array zu speichen,
wenn der zugehörige string benutzt wird.
Es haperte aber an der Umsetzung, auserdem erschien es mir zu kompliziert.
Vieleicht gibt es ja eine möglichkeit geziehlt strings zu entfernen ...
ich hoffe, mir kann jemand helfen
thx schmitzlipp
Die Welt hat sich weiter gedreht !!
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#2

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 17:07
Du könntest Dir ein zweites Array mit der gleichen Länge erstellen.

TFragen_erledigt = Array[1...] of Boolean

Wenn Du eine Frage gestellt hast markierst Du den Eintrag mit true
Wenn Du eine neue Frage auswählst, schaust Du nach ob der Eintrag true oder false
in dem Boolschen Array ist und benutzt die Frage oder verwirst sie.

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#3

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 17:12
Herzlich willkommen in der Delphi-PRAXiS.

Hier noch eine Alternative: wenn du statt eines Arrays eine StringList verwendest, dann könntest du deine Fragen einfach per LoadFromFile() einlesen, per Index auf die einzelnen Fragen und Antworten zugreifen und auch verbrauchte Fragen löschen.

Delphi-Quellcode:
var
  s: TStringList;
  i: Integer;
  fn: TFileName;
begin
  fn := 'FragenAusDemTierreich.txt';
  s := TStringList.Create;
  with s do
  begin
    LoadFromFile(fn);
    while Count > 0 do
    begin
      i := Random(Count);
      ShowMessage(Format('', [Names[i], ValueFromIndex[i]]));
      Delete(i);
    end;
    Free;
  end;
end;
Für ein Array müsstest du dir eine Prozedur schreiben, die das verbrauchte Element durch Zusammenschieben der restlichen Elemente entfernt und die Zahl der Elemente im Array verringert.

Freundliche Grüße vom marabu
  Mit Zitat antworten Zitat
TheAn00bis

Registriert seit: 7. Jun 2004
386 Beiträge
 
#4

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 17:20
Du könntest den entsprechenden String ja wirklich einfach aus dem Array löschen.

Delphi-Quellcode:
procedure DeleteEntry(var pArray: Array of String; pPos: integer); //Prozedur zum Löschen eines beliebigen Eintrags des Arrays
var i, j: integer;
    h: array;
begin
   h := pArray;
   j := 0;
   for i:=low(h) to high(h) do
      begin
         if (i <> pPos) then
             begin
                pArray[j] := h[i];
                inc(j);
             end;
      end;
     setlength(pArray, length(pArray)-1);
end;

function ChoseRandomString: String; //Wählt zufällig einen String aus un löscht ihn
var i:integer;
begin
   i := randomrange(low(StringArray), high(StringArray));
   result := StringArray[i];
   DeleteEntry(StringArray, i);
end;

Hab das mal eben so in die Tastatur gehämmert, bin mir nicht sihcer ob es funktioniert.
Aber vor allem das Prinzip sollte klar werden.
  Mit Zitat antworten Zitat
schmitzlipp

Registriert seit: 6. Nov 2005
9 Beiträge
 
#5

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 18:35
Danke für die schnellen antworten !!!!!!
mir persönlich gefällt die letzte methode am besten, da mir genau so etwas vorschwebte.
'Hab aber heute keinen Bock mehr zu probieren, ich setz mich morgen mal dran.
Nochmals DANKE an ALLE !!!!!!!!
Die Welt hat sich weiter gedreht !!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#6

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 18:35
@TheAn00bis:
Da ein dynamisches Array immer bei null beginnt, kannst du das Low(...) auch durch 0 ersetzen, oder halt weglassen.

Warum das Array doppel kopieren?
es reicht doch, wenn die Daten nach dem zu entfernenden Eintrag um eine Position vorrücken ... also statt immer 200%-1 zu kopieren wird so durchschnittlich nur 50%-1 kopiert/verschoben ... und schneller geht es, wenn man alle nötigen Einträge auf einmal verschiebt (siehe Move)

Delphi-Quellcode:
procedure DeleteEntry(var pArray: Array of String; pPos: integer);
var i: integer;
begin
   for i := pPos to High(pArray) do
      pArray[i] := pArray[i + 1];
   SetLength(pArray, High(pArray));
end;

function ChoseRandomString: String;
var i:integer;
begin
   i := Random(Length(StringArray));
   Result := StringArray[i];
   DeleteEntry(StringArray, i);
end;
Hie mal die Variante mit Move.
Bei deiner For-Variante werdne ja im Grunde alle String 2-mal Kopiert (na ja, bei AnsiStrings werden nur die Refferenzzähler erhöht/verringert, aber bei anderen Stukturen, ohne Refferenzzählung, werden die Inhalte 2mal kopiert).
Delphi-Quellcode:
procedure DeleteEntry(var pArray: Array of String; pPos: integer);
begin
   // String löschen
   pArray[i] := '';
   // die zu nötigen StringPointer vorkopieren
   Move(@pArray[pPos + 1], @pArray[pPos], (High(pArray) - pPos) * SizeOf(Pointer));
   // letzen Pointer löschen ... dieser wurde ja eine Stelle vorkopiert
   Pointer(pArray[High(pArray)]) = nil; SetLength(pArray, High(pArray));
end;

// ich hove bei Move war es Source-Dest-Length und nicht Dest-Source-Length ._.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
TheAn00bis

Registriert seit: 7. Jun 2004
386 Beiträge
 
#7

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 20:43
Zitat von himitsu:
Warum das Array doppel kopieren?
es reicht doch, wenn die Daten nach dem zu entfernenden Eintrag um eine Position vorrücken ... also statt immer 200%-1 zu kopieren wird so durchschnittlich nur 50%-1 kopiert/verschoben ... und schneller geht es, wenn man alle nötigen Einträge auf einmal verschiebt (siehe Move)
Hast vollkommen recht, bin ich vorhin gar nicht drauf gekommen. Move kannte ich gar nicht. Finde den Gebrauch von Pointern in deinem Code sehr schön.
  Mit Zitat antworten Zitat
Hawkeye219

Registriert seit: 18. Feb 2006
Ort: Stolberg
2.227 Beiträge
 
Delphi 2010 Professional
 
#8

Re: "array-Einträge" nicht doppelt auslesen

  Alt 23. Mai 2006, 20:48
Stimmt, die Lösung von himitsu ist die effizienteste. Der Compiler war aber noch nicht ganz zufrieden. Hier die Korrektur mit einigen Sicherheitsabfragen:

Delphi-Quellcode:
type
  TDynStrArray = array of string;

procedure DeleteEntry(var pArray: TDynStrArray; pPos: integer);
begin
  // DAU-Schutz ;-)
  if ((pPos < 0) or (pPos > High(pArray))) then
    exit;
  // String löschen
  pArray[pPos] := '';
  // die nötigen StringPointer verschieben
  if (pPos < High(pArray)) then
    Move(pArray[pPos + 1], pArray[pPos], (High(pArray) - pPos) * SizeOf(Pointer));
  // letzten Pointer löschen ... dieser wurde ja eine Stelle vorkopiert
  Pointer(pArray[High(pArray)]) := nil;
  // Array verkleinern
  SetLength(pArray, High(pArray));
end;
Gruß Hawkeye
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:26 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz