[Purdue-pm] fast table lookup of randomly associated items
Mark Senn
mark at ecn.purdue.edu
Fri Jun 11 22:17:08 PDT 2010
> Say I have a table like the following:
>
> number Item
> 1-5 A
> 6 B
> 7-12 C
> 13-20 D
> 21-25 E
> 26-30 F
>
> Say I then have a random number generator that spits out a number from
> 1-30.
>
> What is the fastest way to look up the item associated with that random
> number?
>
> For more fun, say I want to store that table in a text file what is a
> good way to represent that?
>
> I kicked around some ideas and the easiest solution I could come up with
> is the following. I settled on JSON since it's a bit more portable than
> most and I like its syntax better than YAML.
> ===================================
>
> #!/usr/local/bin/perl
>
> use 5.010;
>
> use strict;
> use warnings;
>
> use File::Slurp;
> use JSON;
>
> my $table = q(table.json);
> my $json_text = read_file( $table ) ;
> my $data = from_json($json_text);
>
> my $number = int(rand(30)+1);
> my $item = q(nothing);
> foreach my $row ( @$data ) {
> if ( $number > $row->[0] ){
> }
> else {
> $item = $row->[1];
> last;
> }
> }
>
> say qq($number associated with $item);
>
> exit(0);
>
> ===================================
> table.json:
>
> [
> [5,"A"],
> [6,"B"],
> [12,"C"],
> [20,"D"],
> [25,"E"],
> [30,"F"]
> ]
Perl 5 solution:
#!/usr/bin/perl
use Modern::Perl;
my @table;
while (<DATA>)
{
chomp;
my ($range, $letter) = split /\s+/;
($range =~ /-/) or $range .= "-$range";
my ($min, $max) = split /-/, $range;
@table[$min..$max] = ($letter) x ($max-$min+1);
}
my $number = int 1 + rand $#table;
say "number $number is associated with $table[$number]";
__END__
1-5 A
6 B
7-12 C
13-20 D
21-25 E
26-30 F
Perl 6 solution:
#!/home/mark/rakudo/perl6
# I couldn't get the following constructs to work in Rakudo on 2010-06-12
#
# my $fh = open $fn, :r
# err die "Can't open $fn for input: $!";
#
# =begin DATA
# ...
# =end
my @table;
my @t =
'1-5 A
6 B
7-12 C
13-20 D
21-25 E
26-30 F'.split(/\n/);
for @t
{
my ($range, $letter) = $_.split(/\s+/);
($range ~~ m/\-/) or $range ~= "-$range";
my ($min, $max) = $range.split(/\-/);
@table[$min..$max] = $letter xx $max-$min+1;
}
say @table[1..^+ at table].pick;
-mark
More information about the Purdue-pm
mailing list