4

I am trying to do basic binary line classification in PHP. (Programming language irrelevant, just more comfortable with PHP).

So basically I have 2 arrays of coordinates:

$classA = [ new Point(1,1), new Point(1,2), new Point(3,3), new Point(1,5) ];
$classB = [ new Point(4,1), new Point(5,2), new Point(4,1), new Point(6,6) ];

I need to iterate through these arrays and get 2 pairs of points each time (A pair consists of a point from classA and another from classB). It is important to get all possible combinations. Once a particular point is in a pair, it cannot be present in another pair.

For example the first two pairs would be:

$pair1 = [$a[0], $b[0]];
$pair2 = [$a[1], $b[1]];

To better explain myself, this is what I need:

enter image description here

When the first pair contains [1,1] , [4,1] all possibile combinations for the other pair are highlighted in yellow.

enter image description here

So far this is what I have:

$classA = [ new Point(1,1), new Point(1,2), new Point(3,3)];
$classB = [ new Point(4,1), new Point(5,2), new Point(4,1)];

$combinations = [];
$pair1 = [];
$pair2 = [];

$n = count($classA);
$m = count($classB);

for ($i=0; $i<$n; $i++){

    for ($j=0; $j<$m; $j++){

        $pair1 = [ $classA[$i], $classB[$j] ];

        for ($z=0; $z<$n; $z++){

            if($z != $i && $z != $j){
                for ($y=0; $y<$m; $y++){
                    if($y != $i && $y != $j){

                        $pair2 = [ $classA[$z], $classB[$y] ];
                        $combinations[] = [$pair1, $pair2];

                    }
                }
            }

        }
    }
}

Apart from being inefficient, this is giving me many duplicates, is there a way to only get unique combinations?

Federkun
  • 36,084
  • 8
  • 78
  • 90
Alex
  • 167
  • 11
  • The order is not important. Pair(a[3],b[2]) is the same as Pair(b[2], a[3]), however it is not the same as Pair(a[2],b[3]) - obviously. – Alex Oct 26 '15 at 14:10

3 Answers3

1

I`d suggest to first create all the possible combinations, then for each pair , replace the row/column with null-s in "all possible combinations" , although it might not be the fastest, but it should work and give you the general idea

$allCombinations = Array();
foreach($classA as $value) {
    $column = Array();
    foreach($classB as $bPart) {
        $column[] = Array($bPart,$value);
    }
    $allCombinations[] = $column;
}

$possibleCombinations = Array();

$sizeA = count($classA);
$sizeB = count($classB);

for($a = 0; $a < $sizeA; $a++) {
    $column = Array();
    for($b = 0; $b < $sizeB; $b++) {
        $temp = $allCombinations;

        for($i = 0;$i < $sizeA;$i++) {
            $temp[$a][$i] = null;
        }

        for($i = 0;$i < $sizeB;$i++) {
            $temp[$i][$b] = null;
        }       

        // for $classA[$a] , $classB[$b] possible combinations are in temp now
        $column[] = $temp;
    }
    $possibleCombinations[] = $column;
}

now , in $possibleCombinations you can see what are the possible combinations for given A/B indexes

In the first loop, it just creates all possible combination, in the second loop, it will first get A and B value , copy all combinations array, then sets column A and row B values to null (because they can not be used, right?) , finally this possible combinations are stored in $temp and added to $possibleCombinations,

example:

$ab = Array($classA[$i],$classB[$j]);
$possibleCombinationsForAB = $possibleCombinations[$i,$j];
ogres
  • 3,660
  • 1
  • 17
  • 16
0

If i understand correctly you want the following: 1. Choose a pair 2. Remove that pair's element's from your arrays 3. Courtesian product of the rest elements

Simplified code that does the above:

$classA = [ 1, 2, 3, 4 ];
$classB = [ 'a', 'b', 'c', 'd'];

function array_cartesian() {
    $_ = func_get_args();
    if(count($_) == 0)
       return array(array());
    $a = array_shift($_);
    $c = call_user_func_array(__FUNCTION__, $_);
    $r = array();
    foreach($a as $v)
        foreach($c as $p)
            $r[] = array_merge(array($v), $p);
    return $r;
}

$pair = [$classA[0], $classB[0]];
unset($classA[0]);
unset($classB[0]);
$pairs = array_cartesian($classA, $classB);
print_r($pairs);

The function is from this question.

Edit.

Output:

Array ( [0] => Array ( [0] => 2 [1] => b ) 
        [1] => Array ( [0] => 2 [1] => c ) 
        [2] => Array ( [0] => 2 [1] => d ) 
        [3] => Array ( [0] => 3 [1] => b ) 
        [4] => Array ( [0] => 3 [1] => c ) 
        [5] => Array ( [0] => 3 [1] => d ) 
        [6] => Array ( [0] => 4 [1] => b ) 
        [7] => Array ( [0] => 4 [1] => c ) 
        [8] => Array ( [0] => 4 [1] => d ) )

Plus the one you choose you have all the possible pairs as described in your tables.

Edit2.

foreach ($classA as $key1 => $value1) {
   foreach ($classA as $key2 => $value2) {
     $A = $classA; // Copying here otherwise your array will be empty
     $B = $classB;
     $pair = [$value1, $value2];
     unset($A[$key1]);
     unset($B[$key2]);
     $pairs = array_cartesian($A, $B);
   }
}
Community
  • 1
  • 1
Akis
  • 193
  • 10
  • Thanks for your help, however this is not returning 2 pairs at a time, and not even all the combinations! I also need all combinations for every pair not just the first one. So for pair(a[0],b[0]) I need all combinations like pair(a[1]. b[1]) - pair(a[1], b[2]), ect. Than for pair(a[0],b[1]), than pair(a[0],b[2]), ect. – Alex Oct 26 '15 at 14:30
  • As you see on output it prints all the pairs with no 1 or a (in your case with no 0,0). If it does not work with your code its cause of the structure pair(). As far as i understand pair() is a custom structure or pseudocode and you have to change the function to support it. – Akis Oct 27 '15 at 06:54
  • Sorry i didn't understood correctly your comment. All you have to do is to call the code in loops and it works nicely. See my edits above – Akis Oct 27 '15 at 07:09
0

Build the cartesian product over both arrays without repeating points, remember array index. This does, however, not handle a same point present in both arrays.

$combinations = [];
$combined = [];

foreach ($classA as $keyA => $valueA) {
    foreach ($classB as $keyB => $valueB) {
        if (!isset($combined[$keyA][$keyB])) {
            $combined[$keyA][$keyB] = $combined[$keyB][$keyA] = true;
            $combinations[$keyA][$keyB] = [$valueA, $valueB];
        }
    }
}

var_dump($combinations);
code-kobold
  • 829
  • 14
  • 18