Split number into chunks according to rank
Question:
A very practical task. I have a number of items that need to be distributed into several stores, according to store rank. So the higher the rank, the more items store will get, so store with rank 1 will get most items and store with rank 100 least.
So the inputs are:
- number of items to distribute
- stores, represented by their rank, can have duplicates as well, and does not follow any pattern, for instance [1, 4, 40]
What I have right now is the following:
- I inverse the ranks, so that smaller number would become biggest (sum(n…) – n)
- I take percentage of each store: inversed_rank sum(inversed_ranks)
- Multiply the amount I need to distribute by the percentage
It works fine on some of the numbers, like:
[1, 4, 40]
1 = 147.2
4 = 137.1
40 = 16.7
Clearly the store with rank 40 gets the least, but with more stores it flattens:
[6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
1 = 17.7
3 = 17.5
6 = 17.4
8 = 17.3
10 = 17.2
10 = 17.2
12 = 17.1
14 = 16.9
16 = 16.8
17 = 16.8
23 = 16.5
24 = 16.4
25 = 16.4
26 = 16.3
28 = 16.2
29 = 16.1
35 = 15.8
40 = 15.5
So store with rank 40 gets only a fraction less than the top.
Does anyone have an idea how to make it a bit more "curved"?
My Python code:
number = 301
ranks = [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
#ranks = [1,4,40]
ranks.sort()
total = sum(ranks)
tmp = 0
reversed = []
for value in ranks:
reversed.append(total - value)
total = sum(reversed)
print('Items per rank:')
for i in range(len(ranks)):
percent = reversed[i] / total
print(str(ranks[i]) + ' = ' + "{:10.1f}".format(percent * number))
tmp = tmp + percent * number
print('')
print('Total = ' + str(tmp))
You may play with it here: https://trinket.io/python/a15c54b978
Would be perfect to have a more math rather than library solution as I will need to translate it into Excel VBA
Solution
Í have also added a factor to control the distribution:
number = 301
ranks = [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
#ranks = [1,4,40]
factor = 1
ranks.sort()
total = sum(ranks)
tmp = 0
max = max(ranks) + 1
reversed = []
for value in ranks:
reversed_value = max - value
reversed_value = pow(reversed_value, factor)
reversed.append(reversed_value)
total = sum(reversed)
print('Items per rank:')
for i in range(len(ranks)):
percent = reversed[i] / total
value = percent * number
print(str(ranks[i]) + ' = ' + "{:10.1f}".format(value))
tmp = tmp + value
print('')
print('Total = ' + str(tmp))
Answers:
Does this work ?
rank= [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
rank_= [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
number = 301
# assuming the point that is the most distant gets the value 0
for i, p in enumerate(rank):
rank[i] = p*-1 + max(rank) + 1
sum = sum(rank)
for i, p in enumerate(rank):
val = p / sum
val *= number
rank[i] = val
for i in range(len(rank)):
print(rank_[i], ": ", rank[i], end="nn")
output:
6: 26.806615776081426
3: 29.104325699745548
24: 13.020356234096692
10: 23.74300254452926
25: 12.254452926208652
12: 22.211195928753177
14: 20.6793893129771
35: 4.595419847328244
40: 0.7659033078880407
16: 17.615776081424936
28: 8.424936386768447
29: 7.659033078880407
17: 16.849872773536894
1: 29.104325699745548
26: 9.956743002544528
23: 12.254452926208652
8: 23.74300254452926
10: 22.211195928753177
A very practical task. I have a number of items that need to be distributed into several stores, according to store rank. So the higher the rank, the more items store will get, so store with rank 1 will get most items and store with rank 100 least.
So the inputs are:
- number of items to distribute
- stores, represented by their rank, can have duplicates as well, and does not follow any pattern, for instance [1, 4, 40]
What I have right now is the following:
- I inverse the ranks, so that smaller number would become biggest (sum(n…) – n)
- I take percentage of each store: inversed_rank sum(inversed_ranks)
- Multiply the amount I need to distribute by the percentage
It works fine on some of the numbers, like:
[1, 4, 40]
1 = 147.2
4 = 137.1
40 = 16.7
Clearly the store with rank 40 gets the least, but with more stores it flattens:
[6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
1 = 17.7
3 = 17.5
6 = 17.4
8 = 17.3
10 = 17.2
10 = 17.2
12 = 17.1
14 = 16.9
16 = 16.8
17 = 16.8
23 = 16.5
24 = 16.4
25 = 16.4
26 = 16.3
28 = 16.2
29 = 16.1
35 = 15.8
40 = 15.5
So store with rank 40 gets only a fraction less than the top.
Does anyone have an idea how to make it a bit more "curved"?
My Python code:
number = 301
ranks = [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
#ranks = [1,4,40]
ranks.sort()
total = sum(ranks)
tmp = 0
reversed = []
for value in ranks:
reversed.append(total - value)
total = sum(reversed)
print('Items per rank:')
for i in range(len(ranks)):
percent = reversed[i] / total
print(str(ranks[i]) + ' = ' + "{:10.1f}".format(percent * number))
tmp = tmp + percent * number
print('')
print('Total = ' + str(tmp))
You may play with it here: https://trinket.io/python/a15c54b978
Would be perfect to have a more math rather than library solution as I will need to translate it into Excel VBA
Solution
Í have also added a factor to control the distribution:
number = 301
ranks = [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
#ranks = [1,4,40]
factor = 1
ranks.sort()
total = sum(ranks)
tmp = 0
max = max(ranks) + 1
reversed = []
for value in ranks:
reversed_value = max - value
reversed_value = pow(reversed_value, factor)
reversed.append(reversed_value)
total = sum(reversed)
print('Items per rank:')
for i in range(len(ranks)):
percent = reversed[i] / total
value = percent * number
print(str(ranks[i]) + ' = ' + "{:10.1f}".format(value))
tmp = tmp + value
print('')
print('Total = ' + str(tmp))
Does this work ?
rank= [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
rank_= [6,3,24,10, 25, 12, 14,35,40, 16,28,29,17,1,26,23,8,10]
number = 301
# assuming the point that is the most distant gets the value 0
for i, p in enumerate(rank):
rank[i] = p*-1 + max(rank) + 1
sum = sum(rank)
for i, p in enumerate(rank):
val = p / sum
val *= number
rank[i] = val
for i in range(len(rank)):
print(rank_[i], ": ", rank[i], end="nn")
output:
6: 26.806615776081426
3: 29.104325699745548
24: 13.020356234096692
10: 23.74300254452926
25: 12.254452926208652
12: 22.211195928753177
14: 20.6793893129771
35: 4.595419847328244
40: 0.7659033078880407
16: 17.615776081424936
28: 8.424936386768447
29: 7.659033078880407
17: 16.849872773536894
1: 29.104325699745548
26: 9.956743002544528
23: 12.254452926208652
8: 23.74300254452926
10: 22.211195928753177