Reputation: 413
Let's say that I want to distribute a number of items (n) into an array of fixed size (x). The difficult part is that I have to distribute the items using a flexibility array.
Assuming that x = 4
, n = 11
and flexibility = [20, 20, 30, 30]
with len(flexibility) == x
.
My question is: How can I distribute the n elements in an array of length equal to x using the percentage defined in f?
What I want at the end is something like:
n = 11
x = 4
flexibility = [20, 20, 30, 30]
distributed = distribute_elements_in_slots(n, x, flexibility)
print(distributed)
# distributed = [2, 2, 3, 4]
In the case of equal flexibility values, the final result will depend on the rule that we decide to apply to use all the item. In the previous case, the final result will be good with [2, 2, 3, 4] and with [2, 2, 4, 3].
Edit: An example of the method that I want to have is as follows:
def distribute_elements_in_slots(n, x, flexibility=[25,25,25,25]):
element_in_slots = []
element_per_percentage = x / 100
for i in range(x):
element_in_slots.append(round(slots_per_point_percentage * flexibility[i])
Edit 2: One of the solutions that I found is the following:
def distribute_elements_in_slots(n, x, flexibility=[25,25,25,25]):
element_in_slots = [f * n / 100 for f in flexibility]
carry = 0
for i in range(len(element_in_slots)):
element = element_in_slots[i] + carry
element_in_slot[i] = floor(element)
carry = element- floor(element)
if np.sum(element_in_slots) < n:
# Here the carry is almost 1
max_index = element_in_slots.index(max(flexibiliyt))
appointments_per_slot[max_index] = appointments_per_slot[max_index] + 1
This will distribute almost evenly the slots based on the flexibility array.
Upvotes: 1
Views: 1368
Reputation: 1
This is an apportionment problem, which has different ways of being solved. See Mathematics of apportionment.
@prune answer implements the Largest Remainder or Hamilton Method.
There are other methods, and some simple examples provided by the US Census Bureau can be found here.
There are Python libraries available at pypi.org that implement different methods:
Upvotes: 0
Reputation: 77885
As Albin Paul did, we need to allocate the whole-number amount for each slot's percentage. The leftovers need to be allocated, largest first.
def distribute_elements_in_slots(total, slots, pct):
# Compute proportional distribution by given percentages.
distr = [total * pct[i] / 100 for i in range(slots)]
# Truncate each position and store the difference in a new list.
solid = [int(elem) for elem in distr]
short = [distr[i] - solid[i] for i in range(slots)]
print(distr)
print(solid)
print(short)
# allocate leftovers
leftover = int(round(sum(short)))
print(leftover)
# For each unallocated item,
# find the neediest slot, and put an extra there.
for i in range(leftover):
shortest = short.index(max(short))
solid[shortest] += 1
short[shortest] = 0
print("Added 1 to slot", shortest)
return solid
n = 11
x = 4
flexibility = [20, 20, 30, 30]
distributed = distribute_elements_in_slots(n, x, flexibility)
print(distributed)
# distributed = [2, 2, 3, 4]
Output:
[2.2, 2.2, 3.3, 3.3]
[2, 2, 3, 3]
[0.2, 0.2, 0.3, 0.3]
1
Added 1 to slot 2
[2, 2, 4, 3]
Upvotes: 2
Reputation: 3419
what you need to do is split the number 11 according to certain percents given in the array so initially it becomes percentage * number(11)
. Then we get remainder and put assign it somewhere which in your case is the last element.
In [10]: [i*n/100 for i in f]
Out[10]: [2.2, 2.2, 3.3, 3.3]
In [11]: b=[i*n/100 for i in f]
In [12]: rem = sum(b) - sum(map(int,b))
In [13]: rem
Out[13]: 1.0
In [24]: b= list(map(int,b))
In [26]: b[-1] +=rem
In [27]: b
Out[27]: [2, 2, 3, 4.0]
Hope it helps. :)
Upvotes: 1