Skip to content

Instantly share code, notes, and snippets.

@jwage
Created April 22, 2014 20:30
Show Gist options
  • Save jwage/11193216 to your computer and use it in GitHub Desktop.
Save jwage/11193216 to your computer and use it in GitHub Desktop.
PHP Cartesian Function
<?php
$attributeValues = array(
'color' => array('Red', 'White', 'Blue'),
'size' => array(1, 2, 3, 4),
'fabric' => array('Cloth', 'Silk')
);
class Cartesian
{
public static function build($set)
{
if (!$set) {
return array(array());
}
$subset = array_shift($set);
$cartesianSubset = self::build($set);
$result = array();
foreach ($subset as $value) {
foreach ($cartesianSubset as $p) {
array_unshift($p, $value);
$result[] = $p;
}
}
return $result;
}
}
print_r(Cartesian::build($attributeValues));
@jwage
Copy link
Author

jwage commented Apr 22, 2014

Array
(
    [0] => Array
        (
            [0] => Red
            [1] => 1
            [2] => Cloth
        )

    [1] => Array
        (
            [0] => Red
            [1] => 1
            [2] => Silk
        )

    [2] => Array
        (
            [0] => Red
            [1] => 2
            [2] => Cloth
        )

    [3] => Array
        (
            [0] => Red
            [1] => 2
            [2] => Silk
        )

    [4] => Array
        (
            [0] => Red
            [1] => 3
            [2] => Cloth
        )

    [5] => Array
        (
            [0] => Red
            [1] => 3
            [2] => Silk
        )

    [6] => Array
        (
            [0] => Red
            [1] => 4
            [2] => Cloth
        )

    [7] => Array
        (
            [0] => Red
            [1] => 4
            [2] => Silk
        )

    [8] => Array
        (
            [0] => White
            [1] => 1
            [2] => Cloth
        )

    [9] => Array
        (
            [0] => White
            [1] => 1
            [2] => Silk
        )

    [10] => Array
        (
            [0] => White
            [1] => 2
            [2] => Cloth
        )

    [11] => Array
        (
            [0] => White
            [1] => 2
            [2] => Silk
        )

    [12] => Array
        (
            [0] => White
            [1] => 3
            [2] => Cloth
        )

    [13] => Array
        (
            [0] => White
            [1] => 3
            [2] => Silk
        )

    [14] => Array
        (
            [0] => White
            [1] => 4
            [2] => Cloth
        )

    [15] => Array
        (
            [0] => White
            [1] => 4
            [2] => Silk
        )

    [16] => Array
        (
            [0] => Blue
            [1] => 1
            [2] => Cloth
        )

    [17] => Array
        (
            [0] => Blue
            [1] => 1
            [2] => Silk
        )

    [18] => Array
        (
            [0] => Blue
            [1] => 2
            [2] => Cloth
        )

    [19] => Array
        (
            [0] => Blue
            [1] => 2
            [2] => Silk
        )

    [20] => Array
        (
            [0] => Blue
            [1] => 3
            [2] => Cloth
        )

    [21] => Array
        (
            [0] => Blue
            [1] => 3
            [2] => Silk
        )

    [22] => Array
        (
            [0] => Blue
            [1] => 4
            [2] => Cloth
        )

    [23] => Array
        (
            [0] => Blue
            [1] => 4
            [2] => Silk
        )

)

@Hywan
Copy link

Hywan commented Apr 23, 2014

What about an iterator? Would be much better for memory usage. An implementation exists here: Hoa\Math\Combinatorics\Combination\CartesianProduct. Thus:

$product = new Hoa\Math\Combinatorics\Combination\CartesianProduct(
    ['Red', 'White', 'Blue'],
    [1, 2, 3, 4],
    ['Cloth', 'Silk']
);

foreach($product as $i => $tuple)
    echo $i, ' = (', implode(', ', $tuple), ')', "\n";

would be product:

0 = (Red, 1, Cloth)
1 = (White, 1, Cloth)
2 = (Blue, 1, Cloth)
3 = (Red, 2, Cloth)
4 = (White, 2, Cloth)
5 = (Blue, 2, Cloth)
6 = (Red, 3, Cloth)
7 = (White, 3, Cloth)
8 = (Blue, 3, Cloth)
9 = (Red, 4, Cloth)
10 = (White, 4, Cloth)
11 = (Blue, 4, Cloth)
12 = (Red, 1, Silk)
13 = (White, 1, Silk)
14 = (Blue, 1, Silk)
15 = (Red, 2, Silk)
16 = (White, 2, Silk)
17 = (Blue, 2, Silk)
18 = (Red, 3, Silk)
19 = (White, 3, Silk)
20 = (Blue, 3, Silk)
21 = (Red, 4, Silk)
22 = (White, 4, Silk)
23 = (Blue, 4, Silk)

@jwage
Copy link
Author

jwage commented Apr 18, 2015

👍

@jamshedhossan9
Copy link

jamshedhossan9 commented Aug 16, 2017

If i need a certain amount of data, what should i do?
suppose i need maximum 20 data instead of 24 from you above example, then what should i do?

@crona2011
Copy link

crona2011 commented Aug 25, 2017

There looks to be 24 combinations; for the universe to balanced 24 must be returned. If you do not want all of them you can slice off the ones you don't want. $array = array_slice($array, 0, 20); or $array = array_slice($array, 4, 24);.

@crona2011
Copy link

crona2011 commented Aug 25, 2017

btw @jwage

return CartesianProduct::build([
      $this->xmlProvider()[0],
      $this->validElementNameProvider()[0],
      $this->invalidElementNameProvider()[0]
]);

nice one.

@ostrolucky
Copy link

Here's pretty interesting implementation https://github.com/PatchRanger/cartesian-iterator

@ganesha316
Copy link

ganesha316 commented Sep 24, 2020

Amazing. Thanks a Ton

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment