Price list behind API

# 20210208 Raku programming solution

my \minDelta = 1;
 
sub getMaxPrice { @_.max }

sub getPRangeCount(@prices,\min,\max) { +@prices.grep: min ≤ * ≤ max }

sub get5000(@prices, $min, $max is copy, \n) {
   my $count = getPRangeCount(@prices, $min, $max);
   my $delta = ($max - $min) / 2;
   while $count != n && $delta ≥ minDelta/2 {
      $count > n ?? ($max -= $delta) !! ($max += $delta);
      $count = getPRangeCount(@prices, $min, $max); 
      $delta /= 2;
   }
   $max, $count
}

sub getAll5000(@prices, \min, \max, \n) {
   my ( $pmax, $pcount ) = get5000(@prices, min, max, n);
   my @res = [ min, $pmax, $pcount ] , ;
   while $pmax < max {
      my $pmin = $pmax + 1;
      ( $pmax, $pcount ) = get5000(@prices, $pmin, max, n);
      $pcount == 0 and note "Price list from $pmin has too many duplicates.";
      @res.push: [ $pmin, $pmax, $pcount ];
   } 
   @res
} 

my $numPrices = (99000..101001).roll;
my \maxPrice  = 1e5;
my @prices    = (1..$numPrices+1).roll xx $numPrices ;

my $actualMax = getMaxPrice(@prices);
say "Using $numPrices items with prices from 0 to $actualMax:";

my @res = getAll5000(@prices, 0, $actualMax, 5000);
say "Split into ", +@res, " bins of approx 5000 elements:";

for @res -> @row {
   my ($min,$max,$subtotal) = @row;
   $max = $actualMax if $max > $actualMax ;
   printf "  From %6d to %6d with %4d items\n", $min, $max, $subtotal 
}

Output:

Using 99506 items with prices from 0 to 99507:
Split into 20 bins of approx 5000 elements:
  From      0 to   4983 with 5000 items
  From   4984 to  10034 with 5003 items
  From  10035 to  15043 with 4998 items
  From  15044 to  20043 with 5001 items
  From  20044 to  24987 with 5001 items
  From  24988 to  30000 with 4998 items
  From  30001 to  34954 with 5000 items
  From  34955 to  40018 with 5000 items
  From  40019 to  45016 with 5000 items
  From  45017 to  49950 with 5000 items
  From  49951 to  54877 with 4999 items
  From  54878 to  59880 with 5002 items
  From  59881 to  64807 with 5001 items
  From  64808 to  69800 with 5000 items
  From  69801 to  74897 with 5000 items
  From  74898 to  79956 with 5002 items
  From  79957 to  85037 with 5000 items
  From  85038 to  90118 with 5001 items
  From  90119 to  95169 with 5001 items
  From  95170 to  99507 with 4470 items

Last updated