如何平展multidimensional array?

在PHP中,是否有可能在不使用recursion或引用的情况下压扁(双/多)维数组?

我只对值有兴趣,所以可以忽略这些键,我正在考虑array_map()array_values()

您可以使用标准PHP库(SPL)来“隐藏”recursion。

 $a = array(1,2,array(3,4, array(5,6,7), 8), 9); $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a)); foreach($it as $v) { echo $v, " "; } 

版画

 1 2 3 4 5 6 7 8 9 

PHP 5.3开始 ,最短的解决scheme似乎是array_walk_recursive()和新的闭包语法:

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

二维数组的解决scheme

请试试这个:

 $array = your array $result = call_user_func_array('array_merge', $array); echo "<pre>"; print_r($result); 

编辑:21八月-13

以下是适用于multidimensional array的解决scheme:

 function array_flatten($array) { $return = array(); foreach ($array as $key => $value) { if (is_array($value)){ $return = array_merge($return, array_flatten($value)); } else { $return[$key] = $value; } } return $return; } $array = Your array $result = array_flatten($array); echo "<pre>"; print_r($result); 

参考: http : //php.net/manual/en/function.call-user-func-array.php

为了平滑W / Orecursion(按照您的要求),您可以使用堆栈 。 当然,你可以把它放入它自己的函数array_flatten 。 以下是一个无w / o键的版本:

 function array_flatten(array $array) { $flat = array(); // initialize return array $stack = array_values($array); // initialize stack while($stack) // process stack until done { $value = array_shift($stack); if (is_array($value)) // a value to further process { $stack = array_merge(array_values($value), $stack); } else // a value to take { $flat[] = $value; } } return $flat; } 

元素按其顺序处理。 因为子元素将被移动到栈顶,它们将被处理。

也可以考虑密钥,但是,您需要一个不同的策略来处理堆栈。 这是需要的,因为你需要处理子数组中可能的重复键。 相关问题中的类似答案: PHP在保存键的同时遍历multidimensional array

我没有特别的确定,但是我在过去已经testing过了: RecurisiveIterator确实使用了recursion,所以这取决于你真正需要的东西。 应该可以创build一个基于堆栈的recursion迭代器:

 foreach(new FlatRecursiveArrayIterator($array) as $key => $value) { echo "** ($key) $value\n"; } 

演示

我没有做到这一点,实现基于RecursiveIterator的堆栈,我认为这是一个不错的主意。

使用recursion。 希望看到它是多么复杂,一旦你看到多么复杂,你对recursion的恐惧就会消散。

 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> 

只是想我会指出这是一个折叠,所以可以使用array_reduce:

 array_reduce($my_array, 'array_merge', array()); 

编辑:请注意,这可以组成扁平化任何数量的级别。 我们可以用几种方法来做到这一点:

 // Reduces one level $concat = function($x) { return array_reduce($x, 'array_merge', array()); }; // We can compose $concat with itself $n times, then apply it to $x // This can overflow the stack for large $n $compose = function($f, $g) { return function($x) use ($f, $g) { return $f($g($x)); }; }; $identity = function($x) { return $x; }; $flattenA = function($n) use ($compose, $identity, $concat) { return function($x) use ($compose, $identity, $concat, $n) { return ($n === 0)? $x : call_user_func(array_reduce(array_fill(0, $n, $concat), $compose, $identity), $x); }; }; // We can iteratively apply $concat to $x, $n times $uncurriedFlip = function($f) { return function($a, $b) use ($f) { return $f($b, $a); }; }; $iterate = function($f) use ($uncurriedFlip) { return function($n) use ($uncurriedFlip, $f) { return function($x) use ($uncurriedFlip, $f, $n) { return ($n === 0)? $x : array_reduce(array_fill(0, $n, $f), $uncurriedFlip('call_user_func'), $x); }; }; }; $flattenB = $iterate($concat); // Example usage: $apply = function($f, $x) { return $f($x); }; $curriedFlip = function($f) { return function($a) use ($f) { return function($b) use ($f, $a) { return $f($b, $a); }; }; }; var_dump( array_map( call_user_func($curriedFlip($apply), array(array(array('A', 'B', 'C'), array('D')), array(array(), array('E')))), array($flattenA(2), $flattenB(2)))); 

当然,我们也可以使用循环,但是这个问题要求在array_map或array_values的行上使用combinator函数。

简单直接的答案

 function flatten_array(array $array) { return iterator_to_array( new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array))); } 

用法:

 $array = [ 'name' => 'Allen Linatoc', 'profile' => [ 'age' => 21, 'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ] ] ]; print_r( flatten_array($array) ); 

输出(在PsySH中):

 Array ( [name] => Allen Linatoc [age] => 21 [0] => Call of Duty [1] => Titanfall [2] => Far Cry ) 

现在,你现在怎么处理钥匙呢? 干杯


编辑 (2017-03-01)

引用Nigel Alderton的关心/问题:

只是为了澄清,这保留了键(即使是数字的),所以具有相同键的值将会丢失。 例如$array = ['a',['b','c']]变成Array ([0] => b, [1] => c )'a'丢失,因为'b'也有一个0的密钥

引用Svish的回答:

只需将false作为第二个参数($use_keys)到iterator_to_array调用

只能展平二维数组:

 $arr = [1, 2, [3, 4]]; $arr = array_reduce($arr, function ($a, $b) { return array_merge($a, (array) $b); }, []); // Result: [1, 2, 3, 4] 

这个解决scheme是非recursion的。 请注意,元素的顺序将有所混合。

 function flatten($array) { $return = array(); while(count($array)) { $value = array_shift($array); if(is_array($value)) foreach($value as $sub) $array[] = $sub; else $return[] = $value; } return $return; } 

尝试以下简单的function:

 function _flatten_array($arr) { while ($arr) { list($key, $value) = each($arr); is_array($value) ? $arr = $value : $out[$key] = $value; unset($arr[$key]); } return (array)$out; } 

所以从这个:

 array ( 'und' => array ( 'profiles' => array ( 0 => array ( 'commerce_customer_address' => array ( 'und' => array ( 0 => array ( 'first_name' => 'First name', 'last_name' => 'Last name', 'thoroughfare' => 'Address 1', 'premise' => 'Address 2', 'locality' => 'Town/City', 'administrative_area' => 'County', 'postal_code' => 'Postcode', ), ), ), ), ), ), ) 

你得到:

 array ( 'first_name' => 'First name', 'last_name' => 'Last name', 'thoroughfare' => 'Address 1', 'premise' => 'Address 2', 'locality' => 'Town/City', 'administrative_area' => 'County', 'postal_code' => 'Postcode', ) 

你可以做ouzo的好东西 :

  $result = Arrays::flatten($multidimensional); 

看: 在这里

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

 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); 
 /** * For merging values of a multidimensional array into one * * $array = [ * 0 => [ * 0 => 'a1', * 1 => 'b1', * 2 => 'c1', * 3 => 'd1' * ], * 1 => [ * 0 => 'a2', * 1 => 'b2', * 2 => 'c2', * ] * ]; * * becomes : * * $array = [ * 0 => 'a1', * 1 => 'b1', * 2 => 'c1', * 3 => 'd1', * 4 => 'a2', * 5 => 'b2', * 6 => 'c2', * * ] */ array_reduce ( $multiArray , function ($lastItem, $currentItem) { $lastItem = $lastItem ?: array(); return array_merge($lastItem, array_values($currentItem)); } ); 

要点片段

对于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; } 

这个版本可以做深,浅或特定的级别:

 /** * @param array|object $array array of mixed values to flatten * @param int|boolean $level 0:deep, 1:shallow, 2:2 levels, 3... * @return array */ function flatten($array, $level = 0) { $level = (int) $level; $result = array(); foreach ($array as $i => $v) { if (0 <= $level && is_array($v)) { $v = flatten($v, $level > 1 ? $level - 1 : 0 - $level); $result = array_merge($result, $v); } elseif (is_int($i)) { $result[] = $v; } else { $result[$i] = $v; } } return $result; } 

因为这里的代码看起来很可怕。 这里是一个函数,它也将一个multidimensional array转换成HTML格式兼容的语法,但更容易阅读。

 /** * Flattens a multi demensional array into a one dimensional * to be compatible with hidden html fields. * * @param array $array * Array in the form: * array( * 'a' => array( * 'b' => '1' * ) * ) * * @return array * Array in the form: * array( * 'a[b]' => 1, * ) */ function flatten_array($array) { // Continue until $array is a one-dimensional array. $continue = TRUE; while ($continue) { $continue = FALSE; // Walk through top and second level of $array and move // all values in the second level up one level. foreach ($array as $key => $value) { if (is_array($value)) { // Second level found, therefore continue. $continue = TRUE; // Move each value a level up. foreach ($value as $child_key => $child_value) { $array[$key . '[' . $child_key . ']'] = $child_value; } // Remove second level array from top level. unset($array[$key]); } } } return $array; } 

如果你真的不喜欢recursion…尝试转移:)

 $a = array(1,2,array(3,4, array(5,6,7), 8), 9); $o = []; for ($i=0; $i<count($a); $i++) { if (is_array($a[$i])) { array_splice($a, $i+1, 0, $a[$i]); } else { $o[] = $a[$i]; } } 

注意:在这个简单的版本中,这不支持数组键。

这是我的解决scheme,使用一个参考:

 function arrayFlatten($array_in, &$array_out){ if(is_array($array_in)){ foreach ($array_in as $element){ arrayFlatten($element, $array_out); } } else{ $array_out[] = $array_in; } } $arr1 = array('1', '2', array(array(array('3'), '4', '5')), array(array('6'))); arrayFlatten($arr1, $arr2); echo "<pre>"; print_r($arr2); echo "</pre>"; 
 <?php //recursive solution //test array $nested_array = [[1,2,[3]],4,[5],[[[6,[7=>[7,8,9,10]]]]]]; /*----------------------------------------- function call and return result to an array ------------------------------------------*/ $index_count = 1; $flatered_array = array(); $flatered_array = flat_array($nested_array, $index_count); /*----------------------------------------- Print Result -----------------------------------------*/ echo "<pre>"; print_r($flatered_array); /*----------------------------------------- function to flaten an array -----------------------------------------*/ function flat_array($nested_array, & $index_count, & $flatered_array) { foreach($nested_array AS $key=>$val) { if(is_array($val)) { flat_array($val, $index_count, $flatered_array); } else { $flatered_array[$index_count] = $val; ++$index_count; } } return $flatered_array; } ?> 

我相信这是最干净的解决scheme,不使用任何突变或不熟悉的类。

 <?php function flatten($array) { return array_reduce($array, function($acc, $item){ return array_merge($acc, is_array($item) ? flatten($item) : [$item]); }, []); } // usage $array = [1, 2, [3, 4], [5, [6, 7]], 8, 9, 10]; print_r(flatten($array)); 

这是一个简单的方法:

 $My_Array = array(1,2,array(3,4, array(5,6,7), 8), 9); function checkArray($value) { foreach ($value as $var) { if ( is_array($var) ) { checkArray($var); } else { echo $var; } } } checkArray($My_Array); 

在PHP5.6及以上版本中,用...运算符array_merge外部数组后,可以使用array_merge二维数组展平。 代码简单明了。

 $a = [[10, 20], [30, 40]]; $b = [["x" => "X", "y" => "Y"], ["p" => "P", "q" => "Q"]]; print_r(array_merge(...$a)); print_r(array_merge(...$b)); Array ( [0] => 10 [1] => 20 [2] => 30 [3] => 40 ) Array ( [x] => X [y] => Y [p] => P [q] => Q ) 

但是当外部数组有非数字键时它不起作用。 在这种情况下,你将不得不首先调用array_values

 $c = ["a" => ["x" => "X", "y" => "Y"], "b" => ["p" => "P", "q" => "Q"]]; print_r(array_merge(...array_values($c))); Array ( [x] => X [y] => Y [p] => P [q] => Q ) 

我需要以HTMLinput格式表示PHPmultidimensional array。

 $test = [ 'a' => [ 'b' => [ 'c' => ['a', 'b'] ] ], 'b' => 'c', 'c' => [ 'd' => 'e' ] ]; $flatten = function ($input, $parent = []) use (&$flatten) { $return = []; foreach ($input as $k => $v) { if (is_array($v)) { $return = array_merge($return, $flatten($v, array_merge($parent, [$k]))); } else { if ($parent) { $key = implode('][', $parent) . '][' . $k . ']'; if (substr_count($key, ']') != substr_count($key, '[')) { $key = preg_replace('/\]/', '', $key, 1); } } else { $key = $k; } $return[$key] = $v; } } return $return; }; die(var_dump( $flatten($test) )); array(4) { ["a[b][c][0]"]=> string(1) "a" ["a[b][c][1]"]=> string(1) "b" ["b"]=> string(1) "c" ["c[d]"]=> string(1) "e" } 

如果你有一个对象数组,并且想用一个节点来压扁它,只需使用这个函数:

 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中,是否有可能在不使用recursion或引用的情况下压扁(双/多)维数组?

至于PHP 7,不是我所知道的。 我创build了一个叫做array_moonwalk的解决scheme,它使用引用和recursion来对multidimensional array进行平坦化和重复数据删除操作,并保留每个用于multidimensional array重build的副本的最深节点的深度。

使用foreach 情况下处理不同深度的叶节点的重复数据删除,也是迄今为止利用array_walk的唯一答案。 没有testing性能。 因人而异。

Interesting Posts