Finding unique array combinations with PHP (permutations)
I was developing a website where people would place horse bets and the system should be able to calculate all the possible permutations based on the user selection. That means: finding all the possible combinations in a two dimensional array. I found a couple of functions but none of them would keep the array keys intact. So, I came up with this idea after a few gray hairs.
It is a mix of recursive array iterations. Consider you have an array like this:
$traits = array
(
'52' => array('Happy', 'Sad', 'Angry', 'Hopeful'),
'21' => array('Outgoing', 'Introverted'),
'12' => array('Tall', 'Short', 'Medium'),
'36' => array('Handsome', 'Plain', 'Ugly')
);
The function should return all the possible combination of traits, exactly like this (keeping the keys intact):
Array
(
[0] => Array
(
[52] => Happy
[21] => Outgoing
[12] => Tall
[36] => Handsome
)
[1] => Array
(
[52] => Happy
[21] => Outgoing
[12] => Tall
[36] => Plain
)
[2] => Array
(
[52] => Happy
[21] => Outgoing
[12] => Tall
[36] => Ugly
)
[3] => Array
(
[52] => Happy
[21] => Outgoing
[12] => Short
[36] => Handsome
)
[4] => Array
(
[52] => Happy
[21] => Outgoing
[12] => Short
[36] => Plain
)
--- and so on....
So, here is the function:
function permutations(array $array, $inb=false)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array[0];
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array, 'recursing');
$return = array();
foreach ($a as $v) {
if($v)
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
if($inb == 'recursing')
$return[] = array_merge(array($v), (array) $v2);
else
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
$x = permutations($traits);
Currently, it only works with numeric array keys. That’s the solution I needed at the moment and I haven’t really tested it with literal keys. Ideas and comments are always welcome.
Thanks to Jon from Stack Overflow for his suggestions and ideas.
