PHP:从数组中连接可能的组合

时间:2012-05-07 21:55:53

标签: php loops combinations

我有一个数组,其中包含不同组合的字符串集/组(在本例中为大写和小写)。我试图循环这个数组 - 使用PHP - 并生成新的字符串连接从原始字符串可以组成的所有可能的组合。

数组如下所示:

Array
(
    [0] => Array
        (
            [0] => ALFA
            [1] => alfa
        )
    [1] => Array
        (
            [0] => BETA
            [1] => beta
        )
    [2] => Array
        (
            [0] => DELTA
            [1] => delta
        )
)

我想要的输出应该是这样的:

ALFA
ALFA BETA
ALFA beta
ALFA DELTA
ALFA delta
ALFA BETA DELTA
ALFA BETA delta
ALFA beta beta
ALFA DELTA BETA
ALFA DELTA beta
ALFA delta BETA
ALFA delta beta
alfa 
alfa BETA
alfa beta
alfa DELTA
alfa delta
alfa BETA DELTA
alfa BETA delta
alfa beta beta
alfa DELTA BETA
alfa DELTA beta
alfa delta BETA
alfa delta beta
BETA
BETA ALFA
BETA alfa
BETA DELTA
BETA delta
BETA ALFA delta
BETA ALFA DELTA
BETA alfa delta
BETA alfa DELTA
BETA DELTA alfa
BETA DELTA ALFA
BETA delta alfa
BETA delta ALFA
beta
beta ALFA
...
...

我花了一整天的时间试图解决这个问题,但却被困住了。任何意见或帮助都非常感谢,谢谢!

3 个答案:

答案 0 :(得分:0)

你可以存储一个只包含这些字符串的小写版本的数组,然后动态大写它(strtoupper完成工作)。

然后使用嵌套的for循环或递归,您将遍历数组的每个元素并echo您需要的各种组合(只需跳过两个层中相同元素的情况)迭代(或递归))

答案 1 :(得分:0)

同意@Mahmoud Al-Qudsi,这似乎是一个奇怪的问题,如果阵列大于琐碎的大小,可能很容易扼杀你的服务器。你确实意识到我们在这里讨论的是阶乘 - 如果你的数组有10个元素,那么单独一个案例中所有10个字符串的排列数就是10个!这是3.5百万添加大小写版本,添加9,8等元素的字符串组合,我们正在讨论非常长的计算。在10个元素数组之后,每增加一个数字,计算次数至少增加10,即3500万,11,350百万,12 ...你得到漂移。

答案 2 :(得分:0)

使用

class CartesianProductIterator implements Iterator {
    protected $iterators;

    function __construct(array $iters) {
        $this->iterators = $iters;
    }

    function rewind() {
        foreach ($this->iterators as $it) {
            $it->rewind();
        }
    }

    function current() {
        $values = array();
        foreach ($this->iterators as $it) {
            $values[] = $it->current();
        }
        return $values;
    }

    function key() {
        return null;
    }

    function next() {
        /*      
        loop them in reverse, but exclude first
        why? example, odometer: 55199
        you always check the rightmost digit first to see if incrementing it would roll it over and need to be "rewound" to 0, 
        which causes the digit to the left to increase as well, which may also cause it to roll over as well, and so on...
        looping in reverse operates from right column to the left.
        we dont rewind the first column because if the leftmost column is on its last element and needs to roll over
        then this iterator has reached its end, and so rewind() needs to be explicitly called 
        */
        for ($i = count($this->iterators) - 1; $i > 0; --$i) {
            $it = $this->iterators[$i];
            $it->next();
            if ($it->valid()) {
                // were done advancing because we found a column that didnt roll over
                return;
            } else {
                $it->rewind();
            }
        }

        //if execution reached here, then all of the columns have rolled over, so we must attempt to roll over the left most column
        $this->iterators[0]->next();
    }

    function valid() {
        return $this->iterators[0]->valid();
    }
}

您可以按照以下方式专门使用它

$iterators = array();
foreach ($arr as $possibleChoicesForOneSlotInACombo) {
    //we add null as a way indicate "no value" as a choice for this slot
    $possibleChoicesForOneSlotInACombo[] = null;
    $iterators[] = new ArrayIterator($possibleChoicesForOneSlotInACombo);
}

foreach (new CartesianProductIterator($iterators) as $combo) {
    //filter out the possible nulls that might exist in this combo
    $strings = array_filter($combo, 'is_string');

    // make sure something exists, maybe they were all null
    if ($strings) {
        echo join(' ', $strings), "\n";
    }
}