Menu Categories Author

Nubis Novem

Consulting On Cloud Nine

Perl: random order list howto

First Perl recipe here, to our best knowledge. The idea is very simple and obvious: using random function rand for randomly ordering values inside a sort pipeline. It could be used for any Perl lists or arrays random ordering, though we decided to sort hash array keys (as we tend to use that a lot in a form of hash array references). Typically, we refrain from injecting our code with calls to standalone modules and libraries (like List::Util::shuffle in this case) to avoid extra dependencies when there is no reasonable need for that.

When no sort is used, keysdoes produce a list of hash key values that would be not in any particular order. You may say that is random. But, the problem is that pseudo-random order of keys would repeat itself every time you retrieve them. Say we have $thash as a predefined hash array reference and would like to see the key values printed by executing the script several times:

#!perl

use strict;

my $thash = {
   a1 => 1,
   b2 => 2,
   c3 => 3,
   c4 => 4,
   c5 => 5
};

foreach my $key ( keys %{$thash} ) {
   print $key . " ";
}

print "\n";
$ perl t1.pl
b2 a1 c5 c3 c4

$ perl t1.pl
b2 a1 c5 c3 c4

$ perl t1.pl
b2 a1 c5 c3 c4

$ perl t1.pl
b2 a1 c5 c3 c4

Every time we called the script the key order remained the same. That may be because of the way key hashed codes are computed by Perl’s hash algorithm.

Now let us get to the business. We will use rand to generate a random fractional number in a range of 0 to 1. We will apply that randomness by lexical comparison via cmp with ‘0.5’. Note, this sort happens absolutely independent of the actual key values. This would provide a flow of wacky ordering decisions with 50% chances a key is sorted one direction or the other (sort of what we need, eh). We are not completely married to this being a most efficient solution, but it has greatest quality of them all: it works!

#!perl

use strict;

my $thash = {
   a1 => 1,
   b2 => 2,
   c3 => 3,
   c4 => 4,
   c5 => 5
};

foreach my $key ( sort { rand cmp 0.5 } keys %{$thash} ) {
   print $key . " ";
}

print "\n";

Or, we can use a more elegant one-liner with join, sort and keys pipeline. While cmp is replaced with a numeric comparison > “greater than”:

#!perl

use strict;

my $thash = {
   a1 => 1,
   b2 => 2,
   c3 => 3,
   c4 => 4,
   c5 => 5
};

print join(' ', sort { rand > 0.5 } keys %{$thash} ) . "\n";

The output is similar for both code snippets. Or, should we say it is random and probably different from the one before, every time it runs:

$ perl t1.pl
a1 c4 c5 c3 b2

$ perl t1.pl
a1 c3 c5 c4 b2

$ perl t1.pl
a1 c4 c3 b2 c5

$ perl t1.pl
a1 b2 c5 c4 c3

$ perl t1.pl
c5 a1 c3 c4 b2

$ perl t1.pl
a1 c4 c5 c3 b2

$ perl t1.pl
b2 a1 c5 c3 c4

$ perl t1.pl
c5 a1 b2 c4 c3

$ perl t1.pl
a1 b2 c4 c3 c5

$ perl t1.pl
a1 c4 c5 c3 b2

Leave a Reply

Your email address will not be published. Required fields are marked *