Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get a randomly selected hash key in Perl 6?

A quick and hopefully easy question:

I need the means to select from among a given set of hash keys at random. The perl6.org documentation on neither rand nor Hash offer many hints.

my %a = 1,2,3,4,5,6;

Given the above,

%a.keys;

returns (5 1 3) and if I simply try

%a.rand;

I get a pseudorandom float rather than any one key.

I eventually cobbled together %a.keys[Int(%a.elems.rand)], but was hoping for something simpler.

like image 287
Joshua Eric Turcotte Avatar asked Jan 30 '16 03:01

Joshua Eric Turcotte


2 Answers

Use pick or roll, eg

%a.keys.pick
like image 143
Christoph Avatar answered Nov 09 '22 00:11

Christoph


As always, Christoph's answer is correct (he knows Perl 6 well). However, I thought I'd elaborate a little since pick and roll can easily be confused at first.


If you only want one random item, then pick and roll seem identical and can be used interchangeably because they both default to returning one item from the original list or array:

my $rand-keyA = %a.keys.pick;

my $rand-keyB = %a.keys.roll;

However, think of them this way:
pick means "Since there are only N things in this container, I can only pick up to N things at once."
roll means "I have an N-sided dice that I can roll as many times as I want."

my %a = 1,2,3,4,5,6;  # { 1 => 2, 3 => 4, 5 => 6 }
                      # (i.e. keys are 1, 3, and 5)

say %a.keys.pick(2);  # (5 3)
say %a.keys.pick(2);  # (3 1)
say %a.keys.pick(5);  # (3 5 1) no more, because there were only three to pick from
say %a.keys.pick(10); # (3 1 5) 

say %a.keys.roll(5);  # (1 5 1 5 3)           as many "rolls" as you request
say %a.keys.roll(10); # (5 5 1 1 5 5 3 1 3 1) 

pick(*) is an easy way to create a randomly reordered list from an array without having to know how many elements it has:

my @array = <foo bar baz foobar>;

@array.pick(*); # (bar foobar baz foo)

roll(*) is an easy way to create an infinite list whose elements are chosen randomly from the original array:

my @rolls = @array.roll(*);

say @rolls[0];         # foobar
say @rolls[10];        # bar
say @rolls[351];       # baz
say @rolls[19123];     # foobar
say @rolls[1000000];   # bar
say @rolls[1000001];   # bar
say @rolls[1000002];   # foo
like image 29
Christopher Bottoms Avatar answered Nov 09 '22 01:11

Christopher Bottoms