Asked  7 Months ago    Answers:  5   Viewed   37 times

I've had this problem bending my mind for a while now (head cold doesn't help either!), basically I have a PHP array which looks like this example:

$array[0][0] = 'apples';
$array[0][1] = 'pears';
$array[0][2] = 'oranges';

$array[1][0] = 'steve';
$array[1][1] = 'bob';

And I would like to be able to produce from this a table with every possible combination of these, but without repeating any combinations (regardless of their position), so for example this would output

Array 0            Array 1
apples             steve
apples             bob
pears              steve
pears              bob

But I would like for this to be able to work with as many different arrays as possible.

 Answers

37

this is called "cartesian product", php man page on arrays http://php.net/manual/en/ref.array.php shows some implementations (in comments).

and here's yet another one:

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;
}

$cross = array_cartesian(
    array('apples', 'pears',  'oranges'),
    array('steve', 'bob')
);

print_r($cross);
Wednesday, March 31, 2021
 
shin
answered 7 Months ago
74

I would use a recursive function. Here's a (working) example with comments. Hope this works for you!

function sampling($chars, $size, $combinations = array()) {

    # if it's the first iteration, the first set 
    # of combinations is the same as the set of characters
    if (empty($combinations)) {
        $combinations = $chars;
    }

    # we're done if we're at size 1
    if ($size == 1) {
        return $combinations;
    }

    # initialise array to put new values in
    $new_combinations = array();

    # loop through existing combinations and character set to create strings
    foreach ($combinations as $combination) {
        foreach ($chars as $char) {
            $new_combinations[] = $combination . $char;
        }
    }

    # call same function again for the next iteration
    return sampling($chars, $size - 1, $new_combinations);

}

// example
$chars = array('a', 'b', 'c');
$output = sampling($chars, 2);
var_dump($output);
/*
array(9) {
  [0]=>
  string(2) "aa"
  [1]=>
  string(2) "ab"
  [2]=>
  string(2) "ac"
  [3]=>
  string(2) "ba"
  [4]=>
  string(2) "bb"
  [5]=>
  string(2) "bc"
  [6]=>
  string(2) "ca"
  [7]=>
  string(2) "cb"
  [8]=>
  string(2) "cc"
}
*/
Wednesday, March 31, 2021
 
exxed
answered 7 Months ago
93

No recursion necessary:

$arrKeys = array_reverse(['lev1', 'lev2', 'lev3']);
$val = 'foo';

$result = $val;

foreach ($arrKeys as $key) {
    $result = [$key => $result];
}

print_r($result); 

// Array
// (
//     [lev1] => Array
//     (
//         [lev2] => Array
//         (
//             [lev3] => foo
//         )
// 
//     )
// 
// )

Just build the array from the inside out.

Wednesday, March 31, 2021
 
Anax
answered 7 Months ago
51

You use a recursive approach but you do not assign the return value of the function call $this->array_values_recursive($value); anywhere. The first level works, as you modify $arr in the loop. Any further level does not work anymore for mentioned reasons.

If you want to keep your function, change it as follows (untested):

function array_values_recursive($arr)
{
  foreach ($arr as $key => $value)
  {
    if (is_array($value))
    {
      $arr[$key] = $this->array_values_recursive($value);
    }
  }

  if (isset($arr['children']))
  {
    $arr['children'] = array_values($arr['children']);
  }

  return $arr;
}
Friday, July 30, 2021
 
kamikaze_pilot
answered 3 Months ago
69

This should work for you:

So what does this code do?

1. How many combinations are there?

So first the question how many combinations are there and the answer is you have to multiply the amount of every array with each other.

So (c = amount1):

carray 1 * carray 2 * ... * carray n

And specific for your example:

carray 1 * carray 2 = 3 * 3 = 9

*1 And if you wonder why I chose c for amount, because of the function count() in php

2. Getting all combinations

How do we get now all combinations with the length of the amount of all arrays?

Well pretty simple, we just loop through all combinations (at the start just an empty combination ([] == array())) which we already have with the next array until we get the desired length which we want, in this case the last iteration of the last array.

So as an example:

Array with the elements (Empty array is '[]'):

[
    [1, 2],
    [3, 4]
]

                               //new combinations for the next iteration
                               |
array NAN*:

    Combinations:
                  - []         |  -> []
                                  |
array 1 [1,2]:       -------------
                    |             |
    Combinations:   v             v
                  - []    + 1  |  -> [1]  
                  - []    + 2  |  -> [2]   
                                  |
array 2 [3,4]:       -------------
                    |             |
    Combinations:   v             v
                  - []    + 3  |  -> [3]
                  - []    + 4  |  -> [4]
                  - [1]   + 3  |  -> [1,3]
                  - [1]   + 4  |  -> [1,4]
                  - [2]   + 3  |  -> [2,3]
                  - [2]   + 4  |  -> [2,4]     
                               //^ All combinations here

* NAN: not a number

So as you can see in the above example we now have all combinations with the length of the amount of all arrays which we have.

But to get only the combinations with the desired length we are overwriting the result array each iteration, so that at the end only the combinations with the expected length are in the results array.

code:

<?php

    $data = [
            35 => ["green", "red", "brown"],
            36 => ["fox", "house", "dog"]
        ];

    $combinations = [[]];
    $comKeys = array_keys($data);


    for ($count = 0; $count < count($comKeys); $count++) {
        $tmp = [];
        foreach ($combinations as $v1) {
            foreach ($data[$comKeys[$count]] as $v2)
                $tmp[] = $v1 + [$comKeys[$count] => $v2];

        }
        $combinations = $tmp;
    }

    print_r($combinations);

?>

output:

Array
(
    [0] => Array
        (
            [35] => green
            [36] => fox
        )

    [1] => Array
        (
            [35] => green
            [36] => house
        )

    [2] => Array
        (
            [35] => green
            [36] => dog
        )

    [3] => Array
        (
            [35] => red
            [36] => fox
        )

    [4] => Array
        (
            [35] => red
            [36] => house
        )

    [5] => Array
        (
            [35] => red
            [36] => dog
        )

    [6] => Array
        (
            [35] => brown
            [36] => fox
        )

    [7] => Array
        (
            [35] => brown
            [36] => house
        )

    [8] => Array
        (
            [35] => brown
            [36] => dog
        )

)
Saturday, August 21, 2021
 
dimi
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :