PHP中的数组组合

PHP*_*Pst 10 php arrays combinatorics multidimensional-array

考虑以下数组:

$a = [['x'], ['y', 'z', 'w'], ['m', 'n']];
Run Code Online (Sandbox Code Playgroud)

如何从中生成以下数组:

$output=[
[[x][y][m]],
[[x][z][n]],
[[x][w][m]],
[[x][y][n]],
[[x][z][m]],
[[x][w][n]],
];
Run Code Online (Sandbox Code Playgroud)

我正在寻找比我更有效的代码.(我目前的代码如下所示)

Car*_*los 8

Here we go. Assuming:

$array = [['x'], ['y', 'z', 'w'], ['m', 'n']];
Run Code Online (Sandbox Code Playgroud)

EDIT: After some performance testing, I concluded the solution I posted before is about 300% slower than OP's code, surely due to nested function call stacking. So here is an improved version of OP's approach, which is around 40% faster:

$count     = array_map('count', $array);
$finalSize = array_product($count);
$arraySize = count($array);
$output    = array_fill(0, $finalSize, []);
$i = 0;
$c = 0;
for (; $i < $finalSize; $i++) {
    for ($c = 0; $c < $arraySize; $c++) {
        $output[$i][] = $array[$c][$i % $count[$c]];
    }
}
Run Code Online (Sandbox Code Playgroud)

It is basically the same code but I used native functions when possible and also took out the loops some functionality that hadn't to be executed on each iteration.


Vol*_*erK 5

"更高效的代码"是这样一个主观的东西.... ;-)
你可以使用迭代器而不是数组,因此完整的结果不必存储在内存中.另一方面,这种解决方案很可能会慢得多.

<?php
class PermIterator implements Iterator {
    protected $mi;
    protected $finalSize, $pos;

    public function __construct(array $src) {
        $mi = new MultipleIterator;
        $finalSize = 1;
        foreach ( $src as $a ) {
            $finalSize *= count($a);
            $mi->attachIterator( new InfiniteIterator(new ArrayIterator($a)) );
        }
        $this->mi = $mi;
        $this->finalSize = $finalSize;
        $this->pos = 0;
    }

    public function current() { return $this->mi->current(); }
    public function key() { return $this->mi->key(); }
    public function next() { $this->pos+=1; $this->mi->next(); }
    public function rewind() { $this->pos = 0; $this->mi->rewind(); }
    public function valid() { return ($this->pos < $this->finalSize) && $this->mi->valid(); }
}


$src = $a = [['x'], ['y', 'z', 'w'], ['m', 'n']];
$pi = new PermIterator($src); // <- you can pass this one around instead of the array
foreach ( $pi as $e ) {
    echo join(', ', $e), "\n";
}
Run Code Online (Sandbox Code Playgroud)

版画

x, y, m
x, z, n
x, w, m
x, y, n
x, z, m
x, w, n
Run Code Online (Sandbox Code Playgroud)

或者作为一个数组(对象),您可以通过整数偏移量访问每个元素

<?php
class PermArray implements  ArrayAccess {
    // todo: constraints and error handling - it's just an example
    protected $source;
    protected $size;

    public function __construct($source) {
        $this->source = $source;
        $this->size = 1;
        foreach ( $source as $a ) {
            $this->size *= count($a);
        }
    }
    public function count() { return $this->size; }

    public function offsetExists($offset) { return is_int($offset) && $offset < $this->size; }
    public function offsetGet($offset) {
        $rv = array();
        for ($c = 0; $c < count($this->source); $c++) {
          $index = ($offset + $this->size) % count($this->source[$c]);
          $rv[] = $this->source[$c][$index];
        }
        return $rv;
    }

    public function offsetSet($offset, $value ){}
    public function offsetUnset($offset){}
}

$pa = new PermArray( [['x'], ['y', 'z', 'w'], ['m', 'n']] );
$cnt = $pa->count();
for($i=0; $i<$cnt; $i++) {
    echo join(', ', $pa[$i]), "\n";
}
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用您的最后一个示例(PermArray 对象),但它似乎无法正常使用此示例: `[['a', 'b'], ['a', 'b'], ['a ', 'b'], ['a'], ['a'], ['a']]`。它只是列出了这两个组合 `a, a, a, a, a, a \ b, b, b, a, a, a` 四次。 (2认同)

PHP*_*Pst 0

<?php
function array_permutation(array $a)
{
    $count = array_map('count', $a);
    $finalSize = 1;

    foreach ($count as $val) {
        $finalSize *= $val;
    }

    $output = [];

    for ($i = 0; $i < $finalSize; $i++) {
        $output[$i] = [];
        for ($c = 0; $c < count($a); $c++) {
            $index = ($i + $finalSize) % $count[$c];
            array_push($output[$i], $a[$c][$index]);
        }
    }
    return $output;
}

$a = [['x'], ['y', 'z', 'w'], ['m', 'n']];
$output= array_permutation($a);
Run Code Online (Sandbox Code Playgroud)