user
There is a list of around 100\_000 prices in the range £0 to £100\_000, expressed
in whole £, (no pence); and prices *may* be duplicated.   
The API allows access to the maximum item price via
function `get_max_price()`; and the number of items equal-to and between two
given price points via function `get_prange_count(pricemin, pricemax)`.  
Assume that for the purposes of testing, you have access to the actual number of priced items to split.

Task

1. Write functions to randomly generate around 100K prices and provide the `get_prange_count` and `get_max_price` API calls.
2. Write functions to provide non-overlapping min and max price ranges that provide product counts where most are close to, but no more than, 5\_000.
3. Ensure that all priced items are covered by all the ranges of prices shown
4. Show ascending price ranges and the number of items covered by each range.
5. Show output from a sample run here.
assistant
**Translation of**: Go

```
# 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

```