Reputation: 12045
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
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