PHP递归调用以生成数组

时间:2019-01-17 05:24:08

标签: php recursion

我正在尝试基于2个数组生成所有可能数据的数组:

$arr1 = ['a', 'b', 'c'];
$arr2 = [true, false];

结果应该类似于:

[
    [
        "a" => true,
        "b" => true,
        "c" => true
    ],
    [
        "a" => true,
        "b" => false,
        "c" => true
    ],
    [
        "a" => true,
        "b" => false,
        "c" => false
    ],
    [
        "a" => true,
        "b" => true,
        "c" => false
    ],
    [
        "a" => false,
        "b" => true,
        "c" => true
    ]
    ...
]

这是我到目前为止所做的:

function generateAllCases($arr1, $arr2)
{
    $resultArr = [];

    foreach ($arr1 as $i => $elm)
    {
        array_shift($arr1);

        foreach ($arr2 as $vis)
        {
            $resultArr[] =
            [
                $elm => $vis
            ];

            $resultArr[] =  $this->generateAllCases($arr1, $arr2);
        }
    }
    return $resultArr;
}

generateAllCases(['a', 'b', 'c'], [true, false]);

我得到了正确的结果,但是数组没有按照我的建议格式化,我尝试了不同的方法来做,但是没有运气获得正确的结果。我无法解决这个问题。

编辑:如果有更好的循环方法,请告诉我。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

似乎您正在寻找$arr2的所有元素中的所有permutations with repetition,其长度为$arr1中的元素数量。

如果是这样,则应该可以进行以下操作:

<?php
declare(strict_types=1);

error_reporting(-1);
ini_set('display_errors', 'On');

function pwr(array $elements, int $k, int $idx = 0, array &$result = []): \Generator
{
    foreach ($elements as $element) {
        $result[$idx] = $element;

        if ($k - $idx > 1) {
            yield from pwr($elements, $k, $idx + 1, $result);
        }
        else {
            yield $result;
        }
    }
}

function gen(array $keys, array $values): \Generator
{
    foreach (pwr($values, \count($keys)) as $set) {
        yield array_combine($keys, $set);
    }
}

// this is just to test the result in a more *visual* way
foreach (gen(range('a', 'j'), [true, false]) as $case) {
    foreach ($case as $k => $v) {
        echo $v ? $k : '_';
    }

    echo "\n";
}

为避免出现内存问题,可以使用yield,但是如果绝对需要数组,请使用iterator_to_array

显然,这种增长非常快(\count($arr2) ** \count($arr1)),因此在使用iterator_to_array时要小心。

演示:https://3v4l.org/l5PRo

答案 1 :(得分:0)

我终于设法做到了。这不是最好的解决方案,但可以。另外,如果我们有10个以上的商品,则由于每次添加新商品都会使它成倍增加,因此该过程开始变慢:

public function generateAllCases($arr1, $arr2, $resultArr, &$index, $firstCall = false)
{
    $shifted = false;

    foreach ($arr1 as $elm)
    {
        foreach ($arr2 as $i => $vis)
        {
            if(!$shifted)
            {
                array_shift($arr1);
                $shifted = true;
            }

            if(!isset($resultArr[$index]) || !isset($resultArr[$index][$elm]))
            {
                $resultArr[$index][$elm] = $vis;
            }
            else 
            {
                $prevItem = $resultArr[$index];
                $index++;
                $resultArr[$index] = $prevItem;
                $resultArr[$index][$elm] = $vis;
            }

            $resultArr = $this->generateAllCases($arr1, $arr2, $resultArr, $index);
        }
        break;
    }

    if($firstCall)
    {
        $allResults = [];
        foreach ($resultArr as $k => $v) 
        {
            $allResults[implode('.', $v)] = $v;
        }

        $allResults = array_values($allResults);
        return $allResults;
    }

    return $resultArr;
}

这样称呼:

$index = 0;
$cases = $rpd->generateAllCases(['a', 'b', 'c'], [true, false], [], $index, true);