![]() |
TStrings mischen nach Fisher-Yates
Es gibt verschiedene Verfahren um eine Liste zu Mischen; also in eine zufällige Unordnung zu bringen.
Der bekannteste Algorithmus dürfte der nach ![]() Man darf sich von der Einfachheit der
Delphi-Quellcode:
nicht täuschen lassen.
procedure FisherYatesShuffle()
Beim Mischen kann man durchaus einige Fehler machen, die leider nicht sofort ins Auge fallen. Zusätzlich sorgt der folgende Code dafür, dass z.B. das Mischen von Memo-Zeilen schnell vonstatten geht. Hintergrund: der Zugriff auf einzelne Strings von [TMemo].Lines, [TListbox].Items oder [TCombobox].Items ist sehr langsam. Durch das Kopieren in ein TStringList-Objekt kann die Gewschwindigkeit massiv gesteiegert werden.
Delphi-Quellcode:
procedure ShuffleTStrings(s:TStrings);
procedure FisherYatesShuffle(x:TStrings); var i : Integer; begin for i := x.Count-1 downto 1 do x.Exchange(i, random(i+1)); end; var t : TStringList; begin Assert(Assigned(s)); if s is TStringList then FisherYatesShuffle(s) else begin t := TStringList.Create; try t.Assign(s); FisherYatesShuffle(t); s.Assign(t); finally t.Free; end; end; end; |
AW: TStrings mischen nach Fisher-Yates
Die Performance-Probleme kommen aber von der falschen Handhabung.
So ist der Zugriff auch schnell
Delphi-Quellcode:
Trotzdem würde ich das immer in einer Funktion auslagern, aufgrund der Trennung von Logik und Anzeige.
Memo1.Lines.BeginUpdate;
try { irgendwas mit dem Memoinhalt machen } finally Memo1.Lines.EndUpdate; end; |
AW: TStrings mischen nach Fisher-Yates
Und das Assert würde ich durch eine Exception ersetzen. Und generell würde ich voraussetzen, dass du einen Nachfahren von TStrings bekommst. Denn ein bisschen Intelligenz sollte man schon voraussetzen können. ;)
|
AW: TStrings mischen nach Fisher-Yates
Das reicht voll und ganz aus.
Delphi-Quellcode:
Und ob es nun wegen dem Assert rummst oder man eine Exception selber schmeißt ist egal, da auch ohne das Gerafffel automatisch eine Exception hochpoppt, wenn x keine gültige Instanz hat.
procedure FisherYatesShuffle( x : TStrings );
var i : Integer; begin x.BeginUpdate; try for i := x.Count - 1 downto 1 do x.Exchange( i, random( i + 1 ) ); finally x.EndUpdate; end; end; Also kann man das bei solch hochkomplexen Routinen auch gleich weglassen. |
AW: TStrings mischen nach Fisher-Yates
Zum Thema Performance: Sortieren von 3000 Zeilen eines TMemo
Code:
Damit ist die ursprüngliche Procedure mehr als 100fach schneller.
Procedure aus Betrag #1: 0,26 Sekunden
Procedure aus vorherigem Betrag: 39,5 Sekunden Zitat:
Die Procedure erwartet ein gültiges Objekt von TStrings bzw. eine Ableitung davon. Sollte der Programmierer fälschlicherweise ein "Nil-Objekt" übergeben, dann ist das Programmierfehler anzusehen; also ein Zustand der "eigentlich" nie auftreten dürfte. Hier eine Exception zu werfen wäre nicht richtig, da es sich nicht um einen erwarteten Fehler handelt. Es bleiben also noch 4 Optionen übrig, wie man damit umgeht: 1.) nichts tun - damit würde es eine Zugriffsverletztung geben. Leider gibt es überhaupt keine Hinweis auf die Ursache der Zugriffsverletzung. Ich weiss nicht, kennt ihr das bescheidene Gefühl, wenn bei einer Livevorführung vor versammelter Mannschaft plötzlich eine Zugriffsverletzung angezeigt wird? Man möchte geradewegs im Boden versinken. 2.) Assert verwenden - man bekommt Dateiname+Zeilennummer; das hilft ungemein bei der Fehlersuche 3.)
Delphi-Quellcode:
Keine schlechte Option; so kann die Procedure keinen Schaden anrichten
if not Assigned(s) then Exit;
4.) Kombination aus 2.) und 3.)
Delphi-Quellcode:
Das scheint mir der beste und sauberste Weg zu sein mit dem nil-Zeiger Problem umzugehen.
if not Assigned(s) then
begin Assert(False, 'ShuffleTStrings(nil)'); Exit; end; |
AW: TStrings mischen nach Fisher-Yates
Zitat:
Zitat:
Zitat:
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:19 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