Price list behind API: Difference between revisions
m (→{{header|Phix}}: default comment) |
|||
Line 17: | Line 17: | ||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
{{trans|Python}} |
{{trans|Python}} |
||
Note that defaulted arguments of the form mx=get_max_price() are not currently supported, hence a slightly hacky workaround. |
Note that defaulted arguments of the form mx=get_max_price() are not currently supported, hence a slightly hacky workaround.<br> |
||
If you defined constant mp = get_max_price(), then mx=mp style parameter defaulting would be fine. |
|||
<lang Phix>constant price_list_size = 99_000 + rand(2_001) - 1, |
<lang Phix>constant price_list_size = 99_000 + rand(2_001) - 1, |
||
price_list = sq_sub(sq_rand(repeat(100_000,price_list_size)),1), |
price_list = sq_sub(sq_rand(repeat(100_000,price_list_size)),1), |
Revision as of 14:09, 25 November 2020
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
- Write functions to randomly generate around 100K prices and provide the
get_prange_count
andget_max_price
API calls. - 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.
- Ensure that all priced items are covered by all the ranges of prices shown
- Show ascending price ranges and the number of items covered by each range.
- Show output from a sample run here.
Phix
Note that defaulted arguments of the form mx=get_max_price() are not currently supported, hence a slightly hacky workaround.
If you defined constant mp = get_max_price(), then mx=mp style parameter defaulting would be fine.
<lang Phix>constant price_list_size = 99_000 + rand(2_001) - 1,
price_list = sq_sub(sq_rand(repeat(100_000,price_list_size)),1), delta_price = 1 -- Minimum difference between any two different prices.
function get_prange_count(integer startp, endp)
return length(filter(price_list,"in",{startp,endp},"[]"))
end function
function get_max_price()
return max(price_list)
end function
function get_5k(integer mn=0, mx=-1, num=5_000)
if mx=-1 then mx = get_max_price() end if -- Binary search for num items between mn and mx, adjusting mx integer count = get_prange_count(mn, mx) atom delta_mx = (mx - mn) / 2 while count != num and delta_mx >= delta_price / 2 do mx = floor(mx + iff(count > num ? -delta_mx : +delta_mx)) {count, delta_mx} = {get_prange_count(mn, mx), delta_mx / 2} end while return {mx, count}
end function
function get_all_5k(integer mn=0, mx=-1, num=5_000)
if mx=-1 then mx = get_max_price() end if -- Get all non-overlapping ranges integer {partmax, partcount} = get_5k(mn, mx, num) sequence result = Template:Mn, partmax, partcount while partmax < mx do integer partmin = partmax + delta_price {partmax, partcount} = get_5k(partmin, mx, num) result = append(result,{partmin, partmax, partcount}) end while return result
end function
printf(1,"Using %d random prices from 0 to %d\n",{price_list_size,get_max_price()}) sequence result = get_all_5k() printf(1,"Splits into %d bins of approx 5000 elements\n",{length(result)}) for i=1 to length(result) do
printf(1," From %8.1f ... %8.1f with %d items.\n",result[i])
end for if length(price_list) != sum(vslice(result,3)) then
printf(1,"\nWhoops! Some items missing:\n")
end if</lang>
- Output:
Using 99714 random prices from 0 to 99999 Splits into 20 bins of approx 5000 elements From 0.0 ... 4977.0 with 5000 items. From 4978.0 ... 10019.0 with 4999 items. From 10020.0 ... 15114.0 with 4999 items. From 15115.0 ... 19987.0 with 4998 items. From 19988.0 ... 25088.0 with 4996 items. From 25089.0 ... 30080.0 with 4995 items. From 30081.0 ... 35117.0 with 5000 items. From 35118.0 ... 40081.0 with 4999 items. From 40082.0 ... 45080.0 with 5000 items. From 45081.0 ... 50181.0 with 5000 items. From 50182.0 ... 55223.0 with 5000 items. From 55224.0 ... 60271.0 with 5000 items. From 60272.0 ... 65102.0 with 4999 items. From 65103.0 ... 70140.0 with 5000 items. From 70141.0 ... 75195.0 with 4997 items. From 75196.0 ... 80203.0 with 4998 items. From 80204.0 ... 85210.0 with 4999 items. From 85211.0 ... 90182.0 with 5000 items. From 90183.0 ... 95268.0 with 4999 items. From 95269.0 ... 104722.0 with 4736 items.
Python
<lang python>import random
- %%Sample price generation
price_list_size = random.choice(range(99_000, 101_000)) price_list = random.choices(range(100_000), k=price_list_size)
delta_price = 1 # Minimum difference between any two different prices.
- %% API
def get_prange_count(startp, endp):
return len([r for r in price_list if startp <= r <= endp])
def get_max_price():
return max(price_list)
- %% Solution
def get_5k(mn=0, mx=get_max_price(), num=5_000):
"Binary search for num items between mn and mx, adjusting mx" count = get_prange_count(mn, mx) delta_mx = (mx - mn) / 2 while count != num and delta_mx >= delta_price / 2: mx += -delta_mx if count > num else +delta_mx mx = mx // 1 # Floor count, delta_mx = get_prange_count(mn, mx), delta_mx / 2 return mx, count
def get_all_5k(mn=0, mx=get_max_price(), num=5_000):
"Get all non-overlapping ranges" partmax, partcount = get_5k(mn, mx, num) result = [(mn, partmax, partcount)] while partmax < mx: partmin = partmax + delta_price partmax, partcount = get_5k(partmin, mx, num) result.append((partmin, partmax, partcount)) return result
if __name__ == '__main__':
print(f"Using {price_list_size} random prices from 0 to {get_max_price()}") result = get_all_5k() print(f"Splits into {len(result)} bins of approx 5000 elements") for mn, mx, count in result: print(f" From {mn:8.1f} ... {mx:8.1f} with {count} items.")
if len(price_list) != sum(count for mn, mx, count in result): print("\nWhoops! Some items missing:")</lang>
- Output:
Using 99838 random prices from 0 to 99999 Splits into 20 bins of approx 5000 elements From 0.0 ... 4876.0 with 4999 items. From 4877.0 ... 9973.0 with 4997 items. From 9974.0 ... 14954.0 with 4999 items. From 14955.0 ... 20041.0 with 4997 items. From 20042.0 ... 25132.0 with 4999 items. From 25133.0 ... 30221.0 with 5000 items. From 30222.0 ... 35313.0 with 5000 items. From 35314.0 ... 40263.0 with 5000 items. From 40264.0 ... 45249.0 with 4997 items. From 45250.0 ... 50264.0 with 5000 items. From 50265.0 ... 55251.0 with 5000 items. From 55252.0 ... 60301.0 with 4997 items. From 60302.0 ... 65239.0 with 5000 items. From 65240.0 ... 70220.0 with 4998 items. From 70221.0 ... 75193.0 with 4999 items. From 75194.0 ... 80229.0 with 4996 items. From 80230.0 ... 85191.0 with 4997 items. From 85192.0 ... 90214.0 with 5000 items. From 90215.0 ... 95249.0 with 4999 items. From 95250.0 ... 104742.0 with 4864 items.