[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