14

How can I randomize the Strings in the StringList similarly how this online tool works. If anyone is familiar with it, check this: http://textmechanic.co/Randomize-List.html

George Chalhoub
  • 14,968
  • 3
  • 38
  • 61
Santos Oliveira
  • 497
  • 1
  • 8
  • 18

3 Answers3

25

One common algorithm to perform a shuffle is the Fisher-Yates shuffle. This generates uniformly distributed permutations.

To implement on a Delphi TStrings object you can use this:

procedure Shuffle(Strings: TStrings);
var
  i: Integer;
begin
  for i := Strings.Count-1 downto 1 do 
    Strings.Exchange(i, Random(i+1));
end;

Now, whilst in theory this will generate uniformly distributed permutations, the actual performance depends heavily on the quality of the random number generator. This is discussed in Knuth's Art of Computer Programming, volume 2, section 3.4.2, Algorithm P.

Further reading:

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
5

Just loop through the stringlist and give each item an different random place:

for i := StringList.Count - 1 downto 1 do
  StringList.Exchange(i, Random(i+1));

[edit] Altered the loop a bit to make the shuffling uniform.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • Yep a true shuffle :) And the most sane one. – Santos Oliveira Dec 22 '12 at 20:38
  • 2
    This answer demonstrates one of the Fisher-Yates errors discussed in Wikipedia, in the ["implementation errors"](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Implementation_errors) section. Although it still yields a shuffled result, which is all the question asked for, it's not a uniform shuffle algorithm. Quality of the RNG is orthogonal to that issue. – Rob Kennedy Dec 23 '12 at 06:39
  • @RobKennedy Okay. Good to know, and the explanation you point to makes it very clear. I've altered the loop a little. Used downto, because it makes the loop simpler. The `+1` is there to prevent an accidental implementation of Sattolo's algorithm. – GolezTrol Dec 23 '12 at 10:43
  • So I deleted all my comments since they are no longer applicable to your answer – David Heffernan Dec 23 '12 at 16:26
  • I found a couple more nice posts on this topic: http://www.codinghorror.com/blog/2007/12/shuffling.html http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html – David Heffernan Dec 23 '12 at 22:29
  • Thanks, but especially the first link is more applicable to the answer by Trident. – GolezTrol Dec 23 '12 at 23:53
-4

To randomize a TStrings, create a comparer from TComparer with random result value, and sort the TStrings with it.

/// The Comparer
TMyShuffleComparer= class(TComparer<string>)
public
  function Compare(const Left, Right: string): Integer; override;
end;

/// The randomizer 
function TMyShuffleComparer.Compare(const Left, Right: TCard): Integer;
begin
  // To sort, get a random number for compare result
  Result := Random(100) - 50;
end;

/// How to call the comparer
procedure TMyStrings.Shuffle;
begin
 Sort(TMyShuffleComparer.Create);
end;

or to call directly:

  /// Shuffle
  MyString.Sort(TMyShuffleComparer.Create);
TridenT
  • 4,879
  • 1
  • 32
  • 56
  • 4
    -1 A sort compare function needs to define a total order. This doesn't. It's a simply terrible idea. I suggest that you delete the answer. Have a read of this, for example: http://blogs.msdn.com/b/oldnewthing/archive/2003/10/23/55408.aspx – David Heffernan Dec 22 '12 at 21:07
  • 3
    Comparison functions that are inconsistent can lead to non-terminating sort functions and buffer overruns. They are not the way to shuffle a list. – Rob Kennedy Dec 23 '12 at 06:28
  • Whilst it is possible to use sorting algos to shuffle, this is not how to do it. Even when you get it right you have much more complex code that is slower than, for example, Fisher-Yates. – David Heffernan Dec 23 '12 at 09:17
  • I tested it according to your remarks and I now understand my mistake on the comparer. Trying to reply to the answer, I've fix my own error ;) – TridenT Dec 23 '12 at 14:44
  • This is a kind of novelty idea, **but**, as @Rob said, your comparing function has to be [**deterministic**](http://technet.microsoft.com/en-us/library/ms178091.aspx) (disregard SQL flavour), otherwise you end up with poorly shuffled resulting list. – Free Consulting Dec 27 '13 at 12:20
  • Also, your selection of random value prefers negative values: [-50, 49] – Free Consulting Dec 27 '13 at 12:24