它是可能的,在PHP中,在不使用递归或引用的情况下扁平化(bi/multi)维数组?

我只对值感兴趣,所以键可以忽略,我认为在array_map()和array_values()的行。


当前回答

对于php 5.2

function flatten(array $array) {
    $result = array();

    if (is_array($array)) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                $result = array_merge($result, flatten($v));
            } else {
                $result[] = $v;
            }
        }
    }

    return $result;
}

其他回答

诀窍是通过引用传递源数组和目标数组。

function flatten_array(&$arr, &$dst) {
    if(!isset($dst) || !is_array($dst)) {
        $dst = array();
    }
    if(!is_array($arr)) {
        $dst[] = $arr;
    } else {
        foreach($arr as &$subject) {
            flatten_array($subject, $dst);
        }
    }
}

$recursive = array('1', array('2','3',array('4',array('5','6')),'7',array(array(array('8'),'9'),'10')));
echo "Recursive: \r\n";
print_r($recursive);
$flat = null;
flatten_array($recursive, $flat);

echo "Flat: \r\n";
print_r($flat);

// If you change line 3 to $dst[] = &$arr; , you won't waste memory,
// since all you're doing is copying references, and imploding the array 
// into a string will be both memory efficient and fast:)

echo "String:\r\n";
echo implode(',',$flat);

如果你有一个对象数组,想用一个节点把它压平,只需要使用这个函数:

function objectArray_flatten($array,$childField) {
    $result = array();
    foreach ($array as $node)
    {
        $result[] = $node;
        if(isset($node->$childField))
        {
            $result = array_merge(
                $result, 
                objectArray_flatten($node->$childField,$childField)
            );
            unset($node->$childField);
        }

    }
    return $result;
}

从PHP 5.3开始,最短的解决方案似乎是array_walk_recursive()与新的闭包语法:

function flatten(array $array) {
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}

使用递归。希望在看到它有多简单的时候,你对递归的恐惧会在你看到它有多简单的时候消失。

function flatten($array) {
    if (!is_array($array)) {
        // nothing to do if it's not an array
        return array($array);
    }

    $result = array();
    foreach ($array as $value) {
        // explode the sub-array, and add the parts
        $result = array_merge($result, flatten($value));
    }

    return $result;
}


$arr = array('foo', array('nobody', 'expects', array('another', 'level'), 'the', 'Spanish', 'Inquisition'), 'bar');
echo '<ul>';
foreach (flatten($arr) as $value) {
    echo '<li>', $value, '</li>';
}
echo '<ul>';

输出:

<ul><li>foo</li><li>nobody</li><li>expects</li><li>another</li><li>level</li><li>the</li><li>Spanish</li><li>Inquisition</li><li>bar</li><ul>

在PHP 5.6及以上版本中,你可以使用array_merge将二维数组平直,然后使用…操作符。代码简单明了。

array_merge(...$a);

这也适用于关联数组的集合。

$a = [[10, 20], [30, 40]];
$b = [["x" => "A", "y" => "B"], ["y" => "C", "z" => "D"]];

print_r(array_merge(...$a));
print_r(array_merge(...$b));

Array
(
    [0] => 10
    [1] => 20
    [2] => 30
    [3] => 40
)
Array
(
    [x] => A
    [y] => C
    [z] => D
)

在PHP 8.0及以下版本中,当外部数组具有非数字键时,数组解包将不起作用。PHP 8.1支持用字符串键解包数组。要支持8.0及以下版本,应该首先调用array_values。

$c = ["a" => ["x" => "A", "y" => "B"], "b" => ["y" => "C", "z" => "D"]];
print_r(array_merge(...array_values($c)));

Array
(
    [x] => A
    [y] => C
    [z] => D
)

更新:基于@ mohammedgharib的评论(适用于PHP 7.3。X和旧的ref)

如果外层数组为空,这将抛出一个错误,因为调用array_merge时参数为零。可以通过添加一个空数组作为第一个参数来避免这种情况。

array_merge([], ...$a);