Flash Thunder
Flash Thunder

Reputation: 12045

recursively - all possibilities - PHP

I've got an array in format:

$array['something_1'] = array('aother_1','aother_2',...,'aother_n')
$array['something_2'] = array('bother_1','bother_2',...,'bother_n')
...
$array['something_m'] = array('zother_1','zother_2',...,'zother_n')

n,m are variable

What I need to do is to create new table that with all sets of something with all posibilities of (x)other ...

$array[] = array('something_1' => 'aother_1','something_2' => 'bother_1', ..., 'something_m' => 'zother_1');
$array[] = array('something_1' => 'aother_2','something_2' => 'bother_1', ..., 'something_m' => 'zother_1');
...
$array[] = array('something_1' => 'aother_n','something_2' => 'bother_n', ..., 'something_m' => 'zother_n');

Basically would like to have all sets of indexes with all possibilities of values.

Some real example:

$input = array(
   'obj1' => array('val1','val2','val3'), 
   'obj2' => array('val4','val5')
);

$output = array(
   [] => array('obj1' => 'val1','obj2' => 'val4'),
   [] => array('obj1' => 'val2','obj2' => 'val4'),
   [] => array('obj1' => 'val3','obj2' => 'val4'),
   [] => array('obj1' => 'val1','obj2' => 'val5'),
   [] => array('obj1' => 'val2','obj2' => 'val5'),
   [] => array('obj1' => 'val3','obj2' => 'val5'),
)

Real cases are much bigger than this example... may contain like 1000 objects and like 20 values per object.

Normally on that example I could use double foreach ... but with 1000 objects, using 1000 foreach seems to be a bit... idiotic :D

Upvotes: 0

Views: 92

Answers (1)

Erwin Moller
Erwin Moller

Reputation: 2408

Here is a solution that takes any combination of n and m, and doesn't use recursive logic (which you dislike).

It effectively keeps track of the number of elements in each sub-array, lowers them by one, and if they reach -1, set back to the original count.

It also uses some link-list like behaviour (terminating when the first key 'curindex' cannot be lowered.)

<?php
$input = array(
   'obj1' => array('val1','val2','val3'), 
   'obj2' => array('val4','val5'),
   'obj3' => array('val6','val7')
);  

// find last key
$keys = array_keys($input);
$lastKey = $keys[count($keys)-1];

// create currentindex and maxindex for each 
$CMI = array();

$former = '';
foreach ($input as $key => $valARR){
    $CMI[$key]["maxindex"] = count($valARR)-1;
    $CMI[$key]["curindex"] = count($valARR)-1;
    // linkedlist like behaviour. obj3 -> obj2 -> obj1 -> ''
    $CMI[$key]["former"] = $former;
    $former = $key;     
}

$output = array();
$bRunning = true;

while ($bRunning){
    $oneCombi = array();
    foreach ($input as $key => $valARR){
        $oneCombi[$key] = $valARR[$CMI[$key]["curindex"]];
    }
    $output[] = $oneCombi;

    // Now lower curindex of last one, all the way up to first one, then quit.
    $bLowering = true;
    $curKey = $lastKey;
    while ($bLowering){
        $CMI[$curKey]["curindex"]--;
        if ($CMI[$curKey]["curindex"] == -1){
            $CMI[$curKey]["curindex"] = $CMI[$curKey]["maxindex"];
            $curKey = $CMI[$curKey]["former"];
            if ($curKey == ''){
                // no more combinations
                $bLowering = false;
                $bRunning = false;
            }
        } else {
            $bLowering = false;
        }
    }
}

// optionally reverse to match your original example:
$output = array_reverse($output);

echo "endresult:<pre>";
var_dump($output);
echo "</pre>";

?>

Upvotes: 1

Related Questions