I would like to order people in balanced groups, but these people belong to a team. I want to know if it is possible to generate groups, but prevent more people from the same team are in the same group.
Example array (people => team)
$total = array(
'Kitten01' => 'A',
'Kitten02' => 'A',
'Kitten03' => 'U',
'Kitten04' => 'U',
'Kitten05' => 'B',
'Kitten06' => 'B',
'Kitten07' => 'M',
'Kitten08' => 'M',
'Kitten09' => 'C',
'Kitten10' => 'C',
'Kitten11' => 'Y',
);
I've used this function:
function partition( $list, $p ) {
$listlen = count( $list );
$partlen = floor( $listlen / $p );
$partrem = $listlen % $p;
$partition = array();
$mark = 0;
for ($px = 0; $px < $p; $px++) {
$incr = ($px < $partrem) ? $partlen + 1 : $partlen;
$partition[$px] = array_slice( $list, $mark, $incr );
$mark += $incr;
}
return $partition;
}
And finally I generate groups:
$max_group = 8;
$people = count($total);
$groups = ceil($people / $max_group);
print_r(partition($total, $groups)) ;
.. and returns this:
Array
(
[0] => Array
(
[Kitten01] => A
[Kitten02] => A
[Kitten03] => U
[Kitten04] => U
[Kitten05] => B
[Kitten06] => B
)
[1] => Array
(
[Kitten07] => M
[Kitten08] => M
[Kitten09] => C
[Kitten10] => C
[Kitten11] => Y
)
)
Is possible to return this?:
Array
(
[0] => Array
(
[Kitten01] => A
[Kitten03] => U
[Kitten05] => B
[Kitten07] => M
[Kitten09] => C
[Kitten11] => Y
)
[1] => Array
(
[Kitten02] => A
[Kitten04] => U
[Kitten06] => B
[Kitten08] => M
[Kitten10] => C
)
)
I hope your help
** Edit: Solution **
With the William's function flip(), I classify all items per team.
with the make_group() function, I take only one Kitten per team and I create a group, the next time that use the make_group() function, I take the rest.
Finally groups are ordered sequentially by team G1(A,U,B,M,C,...), G2(A,U,B,M,C,...) ...
If I merge all these groups and I divide proportionally (if exceeds the maximum permitted per group: 8) I'll never have two people in the same team:
** Final Code **
# groups quantity
$max_group = 8;
$people = count($total);
$groups = ceil($people / $max_group);
$total = flip($total);
$total_group = array();
# merge groups
for($y=0;$y<$groups;$y++)
{
$total_group = array_merge($total_group, make_group($total));
}
# .. and divide proportionally
print_r(partition($total_group, $groups));
The following should work, I believe:
// Your input array
$total = array(
'Kitten01' => 'A',
'Kitten02' => 'A',
'Kitten03' => 'U',
'Kitten04' => 'U',
'Kitten05' => 'B',
'Kitten06' => 'B',
'Kitten07' => 'M',
'Kitten08' => 'M',
'Kitten09' => 'C',
'Kitten10' => 'C',
'Kitten11' => 'Y',
);
// Helper function that flips values and keys, so that your array
// would look like:
// array(
// 'A' => array('Kitten01', 'Kitten02'),
// 'U' => array('Kitten03', 'Kitten04'),
// 'B' => array('Kitten05', 'Kitten06'),
// ...
function flip($array) {
$result = array();
foreach ($array as $k => $v) {
$result[$v][] = $k;
}
return $result;
}
// Make a group from a set of remaining members in teams
function make_group(&$teams) {
$group = array();
// Pick one member per team
foreach ($teams as $k => &$v) {
// If that team still has members, remove the member from the
// team and add it to the group
if ($member = array_shift($v)) {
$group[$member] = $k;
}
}
return $group;
}
$teams = flip($total);
// Repeat as needed
print_r(make_group($teams));
print_r(make_group($teams));