i’m trying to solve this problem:
I’ve 3 percentage (%) stored in three callers: (Caller1, Caller2 and Caller3) like this:
$callers = [
'Caller1' => 50,
'Caller2' => 30,
'Caller3' => 20
];
and I’ve ten numbers
to call, i want to assign the numbers to each caller based on their percentage.
Example:
if numbers are (1, 2, 3 ,4 ,5 ,6 ,7 ,8,9,10), then the calls should be split like the bellow sequence based on their percentage (Note: like the below sequence):
- Caller1: 1,4,7,9,10
- Caller2: 2,5,8
- Caller3: 3,6
my code like this:
class MyClassName
{
// Each caller with their call percentage
private $callers = [
'caller1' => 50,
'caller2' => 30,
'caller3' => 20
];
public $caller1 = array();
public $caller2 = array();
public $caller3 = array();
public function splitCalls(array $numbers)
{
//count numbers
//get spesific number of each percentage
//loop on numbers and push numbers into 3 arrays based on percentage
$count = count($numbers);
$callerOneNumbers = floor(($this->callers['caller1'] / 100) * $count);
$callerTwoNumbers = floor(($this->callers['caller2'] / 100) * $count);
$callerThreeNumbers = floor(($this->callers['caller3'] / 100) * $count);
for ($i = 0; $i <= $count; $i++) {
if (count($this->caller1) < $callerOneNumbers) {
array_push($this->caller1, $numbers[$i]);
$i++;
}
if (count($this->caller2) < $callerTwoNumbers) {
array_push($this->caller2, $numbers[$i]);
$i++;
}
if (count($this->caller3) < $callerThreeNumbers) {
array_push($this->caller3, $numbers[$i]);
$i++;
}
}
}
}
$obj = new MyClassName;
$split = $obj->splitCalls([1, 2, 3, 4, 5, 6, 7, 8,9,10]);
var_dump($obj->caller1);
var_dump($obj->caller2);
var_dump($obj->caller3);
my result like this:
array (size=3)
0 => int 1
1 => int 5
2 => int 9
C:wamp64wwwtest.php:102:
array (size=3)
0 => int 2
1 => int 6
2 => int 10
C:wamp64wwwtest.php:103:
array (size=2)
0 => int 3
1 => int 7
but i want like this:
array (size=3)
0 => int 1
1 => int 4
2 => int 7
3 => int 9
4 => int 10
array (size=2)
0 => int 2
1 => int 5
2 => int 8
array (size=1)
0 => int 3
1 => int 6
any help please
3
Answers
You can be flexible with any amount by calculating a distribution array. Then you know how many items need to go in there and can sequential iterate through it.
Output
JSON encoded for nicer display.
The main problem with your code is that at ever loop, you have
$i++
(in thefor()
loop). This skips 1 array entry per loop (4 and 8 in this example). So a simple solution to your problem would be to change the loop to…as highlighted in the comments, this can cause a problem if the split doesn’t give a nice round split. Changing to using
round
instead offloor
will solve this, although the split can seem unbalanced.e.g with 50, 30, 20 split, 2 items will give [[1], [2], []]. If this is OK, then follow this method.
I support @MarkusZeller’s coding intention to have a "distribution" array. Here is my implementation of the same technique. My snippet converts percentage values into integers. Then while looping the integers will be decremented while also consuming the "numbers" array.
The following approach does not break when the total percentage is something other than 100%. It will endeavor to distribute all numbers and to do so fairly.
Code: (Demo)