# Algorithm for percentage without knowing total number

Suppose there are `n` lines for a hotline.

Whenever a customer calls the hotline, the call is forwarded to one of the `n` lines. And I want to assign percentage of calling to each of the n lines. Suppose there are two lines and one line is assigned 60% and other is 40%, the total number of calls is 10 so the first line would receive 6 calls and second will get 4 calls.

I know the percentage of calling to each line in advance but the problem is that I don't know the number of calls that would be received in a day.

How can I distribute the number of calls without knowing the total calls?

• After line 1 gets 6 calls, give line 2 4 calls. That is, don't care about the actual total count, care about the distribution over the "period" (10, in this case) that you do know. Obviously you can do stuff like alternate lines except the last value, so there isn't a strict wait necessary either. If there's some sort of queue, do the percentage based on current rows in the queue. – Clockwork-Muse Jun 27 '14 at 6:37
• what is "asterisk" and "DID"? – gnat Jun 27 '14 at 7:29
• @Clockwork-Muse: I would suggest rounding on integers here instead of maintaining the 6-4 distribution. Otherwise your distribution is going to be off unless you know you have an exact multiple of 10 calls. E.g. if 6 total calls come in, your suggested approach would assign them all to line A; whereas a more correct approach would be 4 to A and 2 to B (assigned in order ABAABA if you round on integer assignment totals for each line) – Flater May 7 '18 at 12:43

## 5 Answers

Do some bookkeeping about the already taken calls and calculate their distribution over the n lines. This gives you n percentage values (your already achieved distribution), which can be compared to the n percentages you want to achieve. Whenever a new call comes in, assign that call to the line with the highest deviation from the target value (note that as long as you don't hit the given distribution exactly, there is always a line which has too few calls so far, when compared to the target distribution).

For example: after assigning the first call to line 1:

`````` total calls line1      total calls line2    perc.line 1    perc. line 2
1                      0                    100%             0%
*above 60%      *below 40% <- next call to 2
1                      1                    50%             50%
* below 60%:    *above40% next to line1
2                      1                    66%             33%
*above 60%      *below 40% <- next to line 2
2                      2                    50%             50%
* below 60%:    *above40% next to line1
3                      2                    60%             40%
* both hit the mark: next call arbitrary
4                      2                    66%             33%
*above 60%      *below 40% <- next to line 2
4                      3                    57.1%             42.85%
*below 60%      *above 40% <- next to line 1
``````

...

EDIT: This approach could be further improved by not using the absolute difference, but choosing the line which minimizes the sum-of-squares of all deviations. That would also give you a better result in case you reach the target values exactly.

• You may want to change that "as long as" to a more explicit "use a different tiebreaker" reference, FWIW. – DougM Jun 27 '14 at 17:06
• @DougM: see my edit. – Doc Brown Jun 27 '14 at 21:16
• Let's suppose the number of workers is less than 100
• Create an array of workers with a capacity of 100
• Put in that array a worker a number of times equal to the percentage of calls he should get, for example if worker1 should get 30% of all calls, then put him in positions 0 to 29 of the array.
• At the end every position of the array should be used, and workers should appear in the array as many times as the percentage of calls they should get.
• In a loop, generate a random number between 0 and 99, and assign the incoming call to the worker in that position of the array. If worker is busy, repeat.
• That way, out of sheer probability, the calls will be distributed as desired
• In my example, worker1 has a 30/100 chance of getting chosen at any given iteration.

I agree with @DocBrown's solution. Placing it into an algorithm form:

``````for each incoming call:
sort lines ascending by delta* (see footnote below)

// first element in array gets the call
increase number of calls for first element by 1
``````
• Delta is determined by the actual percentage minus the expected percentage of a line. In this way, those with the biggest negative delta are the ones which most require a call to conform with the expected percentage.

For example, in the case in which expected percentages for lines 1 and 2 are respectively 60% and 40%, and their actual percentages are 50% and 50%, you'd see the ordering line 1 followed by line 2, since -10% is less than 10%. Hence line 1 would get the call.

I highly recommend using insertion sort since it performs best when the array is already mostly sorted.

Also, as a minor optimization, if you keep track of the total number of calls thus far, rather than having to calculate the actual percentage of each line, you can simply calculate the total number of calls for that line minus the expected percentage for that line times the total number of calls (delta = t_i - p_i*T). In this case the delta is simply the negative number of calls to achieve the expected percentage.

I hope that clarifies any other doubts.

• thanks @Neil you really helped me but when both hit the mark so which line should i call then,is there any criteria for that. – akku Jun 27 '14 at 9:31
• @akku With my algorithm, you simply take the first always after sorting, meaning the algorithm doesn't care. If you have another criteria to apply, you must make it weigh accordingly when you sort it. In other words, if line number were important, then you should take the delta, multiply by the total number of lines, then add the current line number. That favors higher line numbers, assuming all else being equal. – Neil Jun 27 '14 at 9:39
• @Neil: your answer is fine, but whenever I see someone suggesting to sort an array completely just to find the minimum value, I think "Great Scott, is this really necessary?" – Doc Brown Jun 27 '14 at 11:20
• @DocBrown `O(n)` is what you can expect sorting an already sorted list with insertion sort and `O(n)` is what you'd have to use to find the smallest value. I just assume have it sorted. – Neil Jun 27 '14 at 12:06
• @Neil: just because two algorithms are both O(n), they are not equally simple (or equally fast). – Doc Brown Jun 27 '14 at 21:27

Assumptions as OP stated

1. The number of lines, n, is known and;
2. The % of each line is known

Algorithm Design

1. Define each line by its %

2. Sort each line by its position away from 0 defined as (current % of workers - assigned % of workers) or by random assignation if all lines = 0

3. Forward each call to largest line away from 0

Example: 3 lines with a % of 20, 30 and 50 respectively. At point x in time 1 person calls and since every line is 0 away from 0, it gets randomly assigned - say to line 2 which should hold 30% of all calls. Since line 2 should be holding 30% of all calls and now holds 100% of all calls, its position from 0 increases. The next caller would now be assigned to either line 1 or line 3 etc until equilibrium (0) and thus the loop repeats itself.

This is a naive solution and assumes nothing but would allow percentage based distribution. This solution could be improved upon in a lot of ways but this is the gist of it. I'm not sure if this is what you're looking for but it would give you true distribution.

psuedo code...

``````int running_total_of_calls = 0

//This is hard coded for clarity. You'd most likely want to dynamically populate this array depending and probably distribute the work by alternating workers. Notice how "worker1" appears 6 out of 10 times in the array.
string[] worker = new string
workers = "worker1"
workers = "worker1"
workers = "worker1"
workers = "worker1"
workers = "worker1"
workers = "worker1"
workers = "worker2"
workers = "worker2"
workers = "worker2"
workers = "worker2"

while(1) //run forever
//This is where the distribution occurs.
//first iteration: 0 modulus 10 = 0.
//second: 1 modulus 10 = 1
//third: 2 modulus 10 = 2
//...
//10th: 10 modulus 10 = 0
//11th: 11 modulus 10 = 1
//12th: 12 modulus 10 = 2
//...
int assigned_number = running_total_of_calls % workers.Count //count of workers array
string assigned_worker = workers[assigned_number]
do_work(assigned_worker)
running_total_of_calls = ++running_total_of_calls
``````