3

Using php, I am looking to find a set of unique combinations of a specified length while making sure that no two identical values are present in more than one combination. For example, if I want to find all unique combinations of 3 values (fallback to combinations of 2 values if 3 are not possible) with this array:

$array = array(
    array('1', '2'),
    array('3', '4'),
    array('5', '6'),
);

One possible set of combinations is 123, 456, 14, 15, 16, 24, 25, 26, 34, 35, 36 Note that each number is always combined once and only once with a different number. No duplicate number pairs show up in any combination. Just for clarity's sake, even though 123 and 135 would be unique combinations, only one of these would be returned since the pair 13 occurs in both. The main criteria is that all numbers are eventually grouped with each other number, but only once.

In the final product, the number of arrays and number of values will be notably larger as in:

$array = array(
    array('1', '2', '3', '4', '5', '6', '7', '8'),
    array('9', '10', '11', '12', '13', '14', '15', '16'),
    array('17', '18', '19', '20', '21', '22', '23', '24'),
    array('25', '26', '27', '28', '29', '30', '31')
);

Any help/code to accomplish this would be most appreciated.

UPDATE:

I've taken the brute force approach. First off, I'm using the pear package Math_Combinatorics to create the combinations, starting with a specified maximum size grouping and working my way down to pairs. This way I can get all possible combinations when iterating through to strip out any duplicate clusters within the groups. This code works but is extremely memory intensive. Generating all combinations for an array of 32 values in groups of 6 uses an excess of 1.5G of memory. Is there a better algorithm or approach that will let me use bigger arrays without running out of memory? Here the current state of the code:

require_once 'Combinatorics.php';
$combinatorics = new Math_Combinatorics;
$array = range(1,20,1);
$maxgroup = (6);
$combinations  = $combinatorics->combinations($array, $maxgroup);
for($c=$maxgroup-1;$c>1;$c--)
{
    $comb = $combinatorics->combinations($array, $c);
    $combinations = array_merge($combinations, $comb);
    $comb =  null;
}
for($j=0;$j<sizeof($combinations);$j++)
{
    for($i=sizeof($combinations)-1;$i>=$j+1;$i--)
   {
        $diff = array_intersect($combinations[$j], $combinations[$i]);
        if(count($diff)>1)
        {
            unset($combinations[$i]);
        }
    }
    $combinations = array_values($combinations);
}
print_r($combinations);

1 Answers1

0

Since the structure is just obscuring the numbers which are available, you should first unfold the nested arrays. I'll be kind and do that for you:

$numbers = []
foreach ($arrar as $subarr) {
    foreach ($subarr as $num) {
        $numbers[] = $num;
    }
}

I'm assuming there aren't any duplicate numbers in the input.

Next, you want to perform your algorithm for finding the unique combinations. With array this small, even a recursive solution will work. You don't have to try all the combinatorially-many combinations.

Borealid
  • 86,367
  • 8
  • 101
  • 120
  • Thanks. You assume correctly that there are no duplicate numbers in the input. The structure can easily start out as a single array, I was thinking a multidimensional array would be easier. And for my purposes, there will likely never be more that 100 or so values in that array. My biggest problem is the algorithm for finding the unique combinations. I can't quite wrap my head around how to accomplish that. I'm really new at this. – user1181580 Feb 01 '12 at 02:24