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:\wamp64\www\test.php:102:
array (size=3)
0 => int 2
1 => int 6
2 => int 10
C:\wamp64\www\test.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
CodePudding user response:
The main problem with your code is that at ever loop, you have $i
(in the for()
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...
for ($i = 0; $i < $count;) {
CodePudding user response:
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.
$distribute = function(array $callers, array $data): array {
$distribution = array_values(array_map(fn($percentage) => (int) $percentage/100 * count($data), $callers));
$results = [];
$index = 0;
$length = count($callers);
foreach ($data as $value) {
$added = false;
while (!$added) {
$row = $index % $length;
if ($distribution[$row] > 0) {
$results[$row][] = $value;
$distribution[$row]--;
$added = true;
}
$index ;
}
}
return array_combine(array_keys($callers), $results);
};
echo json_encode($distribute(['Caller1' => 50, 'Caller2' => 30, 'Caller3' => 20], range(1,10)));
Output
JSON encoded for nicer display.
{"Caller1":[1,4,7,9,10],"Caller2":[2,5,8],"Caller3":[3,6]}
CodePudding user response:
Your code has too many hard codes in my opinion. So I think you should create it to be more dynamic. So we can handle a if the data changes.
Here is my suggestion:
<?php
class MyClassName
{
// Each caller with their call percentage
private $callers = [
'caller1' => 50,
'caller2' => 30,
'caller3' => 20
];
public $calls = 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
$numberCount = count($numbers);
$callerCount = count($this->callers);
$j=1;
foreach ($this->callers as $caller => $percent) {
$callerNumber = floor(($percent / 100) * $numberCount);
$this->calls[$caller] = [];
for ($i = $j; $i <= $numberCount; $i =$callerCount) {
$this->calls[$caller][] = $i;
if(count($this->calls[$caller]) >= $callerNumber){
break;
}
}
$j ;
}
}
}
$obj = new MyClassName;
$split = $obj->splitCalls([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var_dump($obj->calls);
output will be:
array(3) {
'caller1' =>
array(4) {
[0] =>
int(1)
[1] =>
int(4)
[2] =>
int(7)
[3] =>
int(10)
}
'caller2' =>
array(3) {
[0] =>
int(2)
[1] =>
int(5)
[2] =>
int(8)
}
'caller3' =>
array(2) {
[0] =>
int(3)
[1] =>
int(6)
}
}
the result is same as you expected.