6

I'm trying to come up with an algorithm in PHP to get all the combinations for a nested array:

Array
(
    [0] => Array
        (
            [0] => Option Object
                (
                    [strValue] => rough
                )

            [1] => Option Object
                (
                    [strValue] => smooth
                )

            [2] => Option Object
                (
                    [strValue] => coarse
                )

        )

    [1] => Array
        (
            [0] => Option Object
                (
                    [strValue] => shiney
                )

            [1] => Option Object
                (
                    [strValue] => mat
                )

        )

    [2] => Array
        (
            [0] => Option Object
                (
                    [strValue] => Large
                )

            [1] => Option Object
                (
                    [strValue] => Medium
                )

            [2] => Option Object
                (
                    [strValue] => Small
                )

            [3] => Option Object
                (
                    [strValue] => very large
                )

        )

)

So I would get something back like:

-rough, shiney, Large

-rough, shiney, Small

-rough, shiney, Medium

-rough, shiney, Very Large

-smooth, shiney, Large

-smooth, shiney, Small

-smooth, shiney, Medium

-smooth, shiney, Very Large

etc (should be 24 in this example)

I've tried through various foreach examples and some basic recursive function, but I seem to be getting no where fast. If anyone could give a basic outline of how to solve this I'd be very grateful, thanks!

wonza
  • 302
  • 1
  • 4
  • 15
  • 1
    and how exactly is your code (which would ideally be added to the question) failing? Because at first sight a set of 3 nested for loops should be all that's needed to solve your problem. – fvu Feb 14 '12 at 00:39
  • 1
    I wouldn't say the arrays are nested, necessarily. They are all contained in a parent array, but they aren't nested with respect to each other. But to create a [cartesian product](http://en.wikipedia.org/wiki/Cartesian_product) using them all, you do want *nested* loops. – JYelton Feb 14 '12 at 00:55
  • possible duplicate of [Finding cartesian product with PHP associative arrays](http://stackoverflow.com/questions/6311779/finding-cartesian-product-with-php-associative-arrays) – deceze Feb 14 '12 at 01:04
  • 1
    Well its not necessarily just 3 foreach's needed. The above can have any number of extra elements – wonza Feb 14 '12 at 01:08
  • Just had a chance try out the cartesian function you mentioned, that worked perfectly thanks! – wonza Feb 14 '12 at 02:07

3 Answers3

9

I just wrote this, that works for arrays of any length..

<?php

function cartesian_product($a) {
  $result = array(array());
  foreach ($a as $list) {
    $_tmp = array();
    foreach ($result as $result_item) {
      foreach ($list as $list_item) {
        $_tmp[] = array_merge($result_item, array($list_item));
      }
    }
    $result = $_tmp;
  }
  return $result;
}


// Let's test this..                                                                                                                                                                                    

header('Content-type: text/plain');

$a = array(
  array('rough','smooth','coarse'),
  array('shiney','mat'),
  array('small','medium','large','x-large'),
);

$result = cartesian_product($a);
foreach ($result as $row) {
  print implode(", ", $row) ."\n";
}

edit: Improved the code a bit..

redShadow
  • 6,687
  • 2
  • 31
  • 34
  • Oh, and just fyi, in Python you would do this: http://stackoverflow.com/questions/533905/get-the-cartesian-product-of-a-series-of-lists-in-python :) – redShadow Feb 14 '12 at 01:41
1

Time to nest some foreach loops!

<?php
$array1 = array('rough', 'smooth', 'coarse');
$array2 = array('shiny', 'matte');
$array3 = array('very large', 'large', 'medium', 'small');

foreach($array1 as $i)
    foreach($array2 as $j)
        foreach($array3 as $k)
            $output[] = "$i, $j, $k";

var_dump($output);
/* ouput
array
  0 => string 'rough, shiny, very large' (length=24)
  1 => string 'rough, shiny, large' (length=19)
  2 => string 'rough, shiny, medium' (length=20)
  3 => string 'rough, shiny, small' (length=19)
  4 => string 'rough, matte, very large' (length=24)
  5 => string 'rough, matte, large' (length=19)
  6 => string 'rough, matte, medium' (length=20)
  7 => string 'rough, matte, small' (length=19)
  8 => string 'smooth, shiny, very large' (length=25)
  9 => string 'smooth, shiny, large' (length=20)
  10 => string 'smooth, shiny, medium' (length=21)
  11 => string 'smooth, shiny, small' (length=20)
  12 => string 'smooth, matte, very large' (length=25)
  13 => string 'smooth, matte, large' (length=20)
  14 => string 'smooth, matte, medium' (length=21)
  15 => string 'smooth, matte, small' (length=20)
  16 => string 'coarse, shiny, very large' (length=25)
  17 => string 'coarse, shiny, large' (length=20)
  18 => string 'coarse, shiny, medium' (length=21)
  19 => string 'coarse, shiny, small' (length=20)
  20 => string 'coarse, matte, very large' (length=25)
  21 => string 'coarse, matte, large' (length=20)
  22 => string 'coarse, matte, medium' (length=21)
  23 => string 'coarse, matte, small' (length=20)
*/
?>
JYelton
  • 35,664
  • 27
  • 132
  • 191
0

Here is the brute force (worst efficiency) algorithm in psuedo-PHP:

$array1 = $array[0];
$array2 = $array[1];
$array3 = $array[2];

$results = array();
for( $i = 0; $i < count( $array1); $i++)
    for( $j = 0; $j < count( $array2); $j++)
        for( $k = 0; $k < count( $array3); $k++)
            $results[] = $array1[$i] . ',' . $array2[$j] . ',' . $array3[$k];
nickb
  • 59,313
  • 13
  • 108
  • 143
  • As I just commented above, its not necessarily just 3 foreach's needed. The above can have any number of extra elements, this is dynamic, so I can't just limit it to 3 nested for/foreach – wonza Feb 14 '12 at 01:15
  • Oh, my mistake. Your title is misleading, as it specifically says 3 arrays. – nickb Feb 14 '12 at 01:20