递归 - 所有可能性 - PHP

时间:2015-09-28 11:45:28

标签: php

我有一个格式的数组:

$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是可变的

我需要做的是创建一个新表,其中包含所有(x)其他所有可能性的东西......

$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');

基本上希望拥有所有可能值的索引集。

一些真实的例子:

$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'),
)

真实案例比这个例子大得多......可能包含1000个对象,每个对象有20个值。

通常在这个例子中我可以使用双foreach ...但是有1000个对象,使用1000 foreach似乎有点......白痴:D

1 个答案:

答案 0 :(得分:1)

这是一个采用n和m的任意组合的解决方案,并且不使用递归逻辑(你不喜欢)。

它有效地跟踪每个子阵列中的元素数量,将它们降低1,如果它们达到-1,则设置回原始计数。

它还使用了一些类似链接列表的行为(当第一个键'curindex'无法降低时终止。)

<?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>";

?>