The second law of thermodynamics, in short version and when read by a programmer, states that “any collection of objects tends not to be sorted” 🙂

We developers, we have a tendency of organizing objects into lists, collections, queues, stacks …

Since you’ll be using the for loop to iterate over elements – why not sort the elements first. What’s more, a sorted list is easier (read: faster) to be searched upon.



For example, for a list of TDeveloper objects you would need developers (instances of TDeveloper) sorted, in the list, by their name, knowledge or salary – or any other property.

That’s boring! I want my lists randomized!

What if you need to randomize the position of elements in a list? Is there an “UnSort” method you can use? Is there a “Randomize” method in TStrings (or similar)? No.

Imagine a deck of cards. Yes, you see it now. How funny the game would be if you would always know what cards are on top of the deck.

Unsorting by sorting 🙂

So how do you unsort a list? Well, by sorting in random order. Here goes:

var //TMyObject = class(TObject) objects : TObjectList<TMyObject>; begin objects := TObjectList<TMyObject>.Create(true); //uses System.Generics.Collections try //"missing" code! //add instances of TMyObjects to the "objects" list... //randomize / UNSORT / SHUFFLE positions objects.Sort(TComparer<TMyObject>.Construct( function(const L,R : TMyObject) : integer begin //returns -1, 0 or 1 result := -1 + Random(3); end )); //"missing" code! //do something with randomized items finally objects.Free; end; end;

That’s it. Call the Sort method by specifying a comparer that would randomly set if an element is less than or greater than the compared element.

This looks lovely, but if you have different lists of different objects that you want to have shuffled, you might want to have a more simple way to call the “unsort” code.

TGenericListHelper

Here’s a sample generic list helper class exposing class methods. There are actually 2 unsort/shuffle methods – so pick the one you prefer better 😉

TGenericListHelper = class class procedure Shuffle<T>(const listOfT : TList<T>); class procedure UnSort<T>(const listOfT : TList<T>); end;

And the implementation part:

class procedure TGenericListHelper.Shuffle<T>(const listOfT: TList<T>); //randomize positions by swapping the position of two elements randomly var randomIndex: integer; cnt: integer; begin Randomize; for cnt := 0 to -1 + listOfT.Count do begin randomIndex := Random(-cnt + listOfT.Count) ; listOfT.Exchange(cnt, cnt + randomIndex) ; end; end; class procedure TGenericListHelper.UnSort<T>(const listOfT: TList<T>); //randomize positions by unsorting begin Randomize; listOfT.Sort(TComparer<T>.Construct( function(const Left, Right : T) : integer begin result := -1 + Random(3); end )); end;

You can, of course, use the above for any list (of any specific type), like:

//"pseudo" code ... type TMyRecord = record b : boolean; i : integer; s : string; end; var intList : TList<integer>; strList : TList<string>; recList : TList<TMyRecord>; begin //add items to lists... //... //shuffle elements TGenericListHelper.Shuffle<integer>(intList); TGenericListHelper.Shuffle<string>(strList); TGenericListHelper.Shuffle<TMyRecord>(recList); end;

Shuffle me gently by a sample …

Here’s a dummy example where a list of letters is displayed in a list box (“ListBox1”), then shuffled and displayed again.

Drop a TLIstBox on a form and have it filled in the OnCreate event of the form:

procedure TMainForm.FormCreate(Sender: TObject); var c : Integer; begin for c := 65 to 90 do ListBox1.Items.Add(CHR(c)+CHR(c)+CHR(c)) ; end;

To make it more OOP (and therefore less clear to read, lol), have a class TMyObject defined as:

type TMyObject = class Value : string; end;

Now, have a TButton and handle its OnClick event to shuffle ListBox1’s elements:

procedure TMainForm.Button1Click(Sender: TObject); var objects : TObjectList<TMyObject>; myO : TMyObject; s : string; begin objects := TObjectList<TMyObject>.Create(true); try for s in ListBox1.Items do begin myO := TMyObject.Create; myO.Value := s; objects.Add(myO); end; //Option 1 objects.Sort(TComparer<TMyObject>.Construct( function(const L,R : TMyObject) : integer begin //returns -1, 0 or 1 result := -1 + Random(3); end )); //option 1 generalized TGenericListHelper.UnSort<TMyObject>(objects); //option 2 TGenericListHelper.Shuffle<TMyObject>(objects); ListBox1.Clear; for myO in objects do ListBox1.Items.Add(myO.Value) ; finally objects.Free; end; end;

If you have a simpler / shorter way to shuffle elements in lists – please do share as a comment…