2

I have an array that looks like this:

$i[0] = ['a', 'b', 'c'];
$i[1] = ['d', 'e'];
$i[2] = ['a', 'b', 'c'];
$i[3] = ['d', 'e'];
$i[4] = ['f', 'g', 'h'];

I want to get all the possible permutations or combinations of this array, but without using the same value twice from two or more sub-arrays. So for instance, the result a d b e f would be possible, but not a d a d f.

I have tried basic permutation algorithms, but I can't wrap my head around how to modify it to do what I want.

Here's what I've got currently:

function array_permutation(array $a){
    $count = array_map('count', $a);
    $finalSize = 1;

    foreach ($count as $val) {
        $finalSize *= $val;
    }

    $output = [];

    for ($i = 0; $i < $finalSize; $i++) {
        $output[$i] = [];
        for ($c = 0; $c < count($a); $c++) {
            $index = ($i + $finalSize) % $count[$c];
            array_push($output[$i], $a[$c][$index]);
        }
    }
    return $output;
}
Emil
  • 7,220
  • 17
  • 76
  • 135

1 Answers1

2

A very simple approach will be plain loop:

function decartProductExclusive($one, $two)
{
   $result = [];
   for($i=0; $i<count($one); $i++)
   {
      for($j=0; $j<count($two); $j++)
      {
         if(!count(array_intersect((array)$one[$i], (array)$two[$j])))
         {
            $result[]=array_merge((array)$one[$i], (array)$two[$j]);
         }
      }
   }
   return $result;
}

function createAssociation()
{
   $args   = func_get_args();
   if(!count($args))
   {
      return [];
   }
   $result = array_shift($args);
   while($array=array_shift($args))
   {
      $result=decartProductExclusive($result, $array);
   }
   return $result;
}

$i[0] = ['a', 'b', 'c'];
$i[1] = ['d', 'e'];
$i[2] = ['a', 'b', 'c'];
$i[3] = ['d', 'e'];
$i[4] = ['f', 'g', 'h'];

$result = call_user_func_array('createAssociation', $i);

(check the fiddle) Your issue is about evaluating Cartesian product, but with condition, that tuple can not contain repeated elements. This condition, however, may be fulfilled without evaluating intersection in each iteration (that will be an overkill). Instead you can filter resulting array, using array_unique(), like in this fiddle.

Alma Do
  • 37,009
  • 9
  • 76
  • 105