Có thể, trong PHP, có thể làm phẳng một mảng (bi / multi) mà không cần sử dụng đệ quy hoặc tham chiếu không?
Tôi chỉ quan tâm đến các giá trị để các khóa có thể bị bỏ qua, tôi đang suy nghĩ theo dòng array_map()
và array_values()
.
Có thể, trong PHP, có thể làm phẳng một mảng (bi / multi) mà không cần sử dụng đệ quy hoặc tham chiếu không?
Tôi chỉ quan tâm đến các giá trị để các khóa có thể bị bỏ qua, tôi đang suy nghĩ theo dòng array_map()
và array_values()
.
Câu trả lời:
Bạn có thể sử dụng Thư viện PHP chuẩn (SPL) để "ẩn" đệ quy.
$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, " ";
}
in
1 2 3 4 5 6 7 8 9
iterator_to_array($it, false)
tránh sự cần thiết cho các foreach.
function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }
Hy vọng điều này sẽ giúp người khác.
Kể từ phiên bản PHP 5.3 , giải pháp ngắn nhất dường như là array_walk_recursive()
với cú pháp đóng mới:
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
use
cú pháp để thực hiện công việc này array_walk_recursive
vì nó sẽ không chấp nhận $userdata
tham số tùy chọn theo tham chiếu
Giải pháp cho mảng 2 chiều
Vui lòng thử điều này:
$array = your array
$result = call_user_func_array('array_merge', $array);
echo "<pre>";
print_r($result);
EDIT: 21-ngày 13 tháng 8
Đây là giải pháp hoạt động cho mảng đa chiều:
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);
Tham chiếu: http://php.net/manual/en/feft.call-user-func-array.php
call_user_func_array('array_merge', [])
(chú ý mảng trống) trả về null và gây ra lỗi cảnh báo php. Đó là một giải pháp khéo léo nếu bạn biết rằng thực tế mảng của bạn sẽ trống, nhưng đó không phải là giả định phổ biến mà nhiều người có thể thực hiện.
$result = $array ?call_user_func_array('array_merge', $array) : [];
Trong PHP 5.6 trở lên, bạn có thể làm phẳng các mảng hai chiều array_merge
sau khi giải nén mảng bên ngoài bằng ...
toán tử. Mã rất đơn giản và rõ ràng.
array_merge(...$a);
Điều này làm việc với bộ sưu tập các mảng kết hợp quá.
$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
)
Nhưng nó không hoạt động khi mảng ngoài có các phím số. Trong trường hợp đó, bạn sẽ phải gọi array_values
trước.
$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
)
Cập nhật: Dựa trên nhận xét của @MohamedGharib
Điều này sẽ đưa ra một lỗi nếu mảng bên ngoài trống, vì array_merge
sẽ được gọi với các đối số bằng không. Có thể tránh được bằng cách thêm một mảng trống làm đối số đầu tiên.
array_merge([], ...$a);
array_merge([], ...$a);
Để làm phẳng đệ quy (như bạn đã yêu cầu), bạn có thể sử dụng một ngăn xếp . Đương nhiên, bạn có thể đặt nó vào một chức năng của chính nó array_flatten
. Sau đây là phiên bản hoạt động với các phím 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;
}
Các yếu tố được xử lý theo thứ tự của chúng. Bởi vì các phần tử con sẽ được di chuyển lên trên cùng của ngăn xếp, chúng sẽ được xử lý tiếp theo.
Tuy nhiên, bạn cũng có thể tính đến các khóa, bạn sẽ cần một chiến lược khác để xử lý ngăn xếp. Điều đó là cần thiết bởi vì bạn cần phải xử lý các khóa trùng lặp có thể có trong các mảng con. Một câu trả lời tương tự trong một câu hỏi liên quan: PHP Đi qua mảng đa chiều trong khi bảo quản các khóa
Tôi không chắc chắn lắm, nhưng tôi đã thử nghiệm điều này trong quá khứ: Việc RecurisiveIterator
sử dụng đệ quy, vì vậy nó phụ thuộc vào những gì bạn thực sự cần. Nên có thể tạo một trình lặp đệ quy dựa trên các ngăn xếp:
foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
echo "** ($key) $value\n";
}
Tôi đã không làm cho đến nay, để thực hiện ngăn xếp dựa trên RecursiveIterator
đó tôi nghĩ là một ý tưởng tốt.
if(!empty($value)){$flat[] = $value}
vào bên trong câu lệnh khác để ngăn trống được thêm vào mảng kết quả. Chức năng tuyệt vời!
Câu trả lời đơn giản và một lót .
function flatten_array(array $array)
{
return iterator_to_array(
new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)));
}
Sử dụng:
$array = [
'name' => 'Allen Linatoc',
'profile' => [
'age' => 21,
'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
]
];
print_r( flatten_array($array) );
Đầu ra (trong PsySH):
Array
(
[name] => Allen Linatoc
[age] => 21
[0] => Call of Duty
[1] => Titanfall
[2] => Far Cry
)
Bây giờ nó khá đẹp đối với bạn cách bạn xử lý các phím. Chúc mừng
EDIT (2017 / 03-01)
Trích dẫn mối quan tâm / vấn đề của Nigel Alderton :
Chỉ cần làm rõ, điều này bảo tồn các khóa (thậm chí cả số) để các giá trị có cùng khóa bị mất. Ví dụ
$array = ['a',['b','c']]
trở thànhArray ([0] => b, [1] => c )
. Các'a'
bị mất bởi vì'b'
cũng có một then chốt của0
Trích dẫn câu trả lời của Svish :
Chỉ cần thêm false làm tham số thứ hai
($use_keys)
vào lệnh gọi iterator_to_array
$array = ['a',['b','c']]
trở thành Array ([0] => b, [1] => c )
. Các 'a'
bị mất bởi vì 'b'
cũng có một chìa khóa của 0
.
false
dưới dạng tham số thứ hai ( $use_keys
) vào iterator_to_array
cuộc gọi.
Sử dụng đệ quy. Hy vọng rằng khi thấy nó không phức tạp như thế nào, nỗi sợ đệ quy của bạn sẽ tan biến khi bạn thấy nó không phức tạp như thế nào.
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>';
Đầu ra:
<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>
Chỉ cần nghĩ rằng tôi chỉ ra rằng đây là một nếp gấp, vì vậy mảng_reduce có thể được sử dụng:
array_reduce($my_array, 'array_merge', array());
EDIT: Lưu ý rằng điều này có thể được soạn thảo để làm phẳng bất kỳ số lượng cấp độ. Chúng tôi có thể làm điều này theo nhiều cách:
// 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))));
Tất nhiên, chúng ta cũng có thể sử dụng các vòng lặp nhưng câu hỏi yêu cầu một hàm tổ hợp dọc theo các dòng của Array_map hoặc Array_values.
fold
chia thành 4 cấp độ hoặc fold . fold
để có được 3 cấp độ hoặc fold . fold . fold
để có được 2 cấp độ, v.v ... Điều này cũng ngăn ngừa các lỗi bị ẩn; ví dụ. nếu tôi muốn làm phẳng một mảng 5D nhưng tôi được cung cấp một mảng 4D, lỗi sẽ kích hoạt ngay lập tức.
$concat
, tôi nghĩ bạn chỉ nên gọi nó $flatten
. array_merge
là tương đương php của concat. Tôi đã cố gắng để được array_concat
thêm vào như một bí danh cho array_merge
.
Giải pháp này là không đệ quy. Lưu ý rằng thứ tự của các yếu tố sẽ được pha trộn một chút.
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;
}
shifting
giá trị ngoài mảng và nối lại nó đến cuối không có ý nghĩa gì nhiều. Tôi đoán bạn muốn array_merge()
thay thế?
Tôi tin rằng đây là giải pháp sạch nhất mà không sử dụng bất kỳ đột biến cũng như các lớp không quen thuộc.
<?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));
Hãy thử chức năng đơn giản sau:
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;
}
Vì vậy, từ đây:
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',
),
),
),
),
),
),
)
bạn lấy:
array (
'first_name' => 'First name',
'last_name' => 'Last name',
'thoroughfare' => 'Address 1',
'premise' => 'Address 2',
'locality' => 'Town/City',
'administrative_area' => 'County',
'postal_code' => 'Postcode',
)
Thủ thuật là vượt qua cả mảng nguồn và mảng đích bằng cách tham chiếu.
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));
}
);
Bạn có thể làm điều đó với goodies ouzo :
$result = Arrays::flatten($multidimensional);
Xem: Tại đây
Nếu bạn thực sự không thích đệ quy ... thay vào đó hãy thử thay đổi :)
$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];
}
}
Lưu ý: Trong phiên bản đơn giản này, điều này không hỗ trợ các phím mảng.
continue
, nó có phần nhanh hơn.
Làm thế nào về việc sử dụng một máy phát đệ quy? https://ideone.com/d0TXCg
<?php
$array = [
'name' => 'Allen Linatoc',
'profile' => [
'age' => 21,
'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
]
];
foreach (iterate($array) as $item) {
var_dump($item);
};
function iterate($array)
{
foreach ($array as $item) {
if (is_array($item)) {
yield from iterate($item);
} else {
yield $item;
}
}
}
Đối với 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;
}
Phiên bản này có thể làm sâu, nông hoặc một số cấp độ cụ thể:
/**
* @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;
}
Bởi vì mã ở đây trông đáng sợ. Đây là một hàm cũng sẽ chuyển đổi một mảng nhiều chiều thành cú pháp tương thích dạng html, nhưng dễ đọc hơn.
/**
* 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;
}
Điều này có thể đạt được bằng cách sử dụng array_walk_recursive
$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
array_walk_recursive($a, function($v) use (&$r){$r[]=$v;});
print_r($r);
Ví dụ hoạt động: - https://3v4l.org/FpIrG
Đây là giải pháp của tôi, sử dụng tài liệu tham khảo:
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;
}
?>
Bất cứ ai đang tìm kiếm một giải pháp thực sự sạch cho việc này; đây là một lựa chọn:
$test_array = array(
array('test' => 0, 0, 0, 0),
array(0, 0, 'merp' => array('herp' => 'derp'), 0),
array(0, 0, 0, 0),
array(0, 0, 0, 0)
);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($test_array));
var_dump( iterator_to_array($it, false) ) ;
Bản in
0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0
Chỉ cần đăng một số giải pháp khác)
function flatMultidimensionalArray(array &$_arr): array
{
$result = [];
\array_walk_recursive($_arr, static function (&$value, &$key) use (&$result) {
$result[$key] = $value;
});
return $result;
}
Nếu bạn muốn giữ chìa khóa của bạn đó là giải pháp.
function reduce(array $array) {
$return = array();
array_walk_recursive($array, function($value, $key) use (&$return) { $return[$key] = $value; });
return $return;
}
Thật không may, nó chỉ xuất ra các mảng lồng nhau cuối cùng, không có các phím giữa. Vì vậy, cho ví dụ sau:
$array = array(
'sweet' => array(
'a' => 'apple',
'b' => 'banana'),
'sour' => 'lemon');
print_r(flatten($fruits));
Đầu ra là:
Array
(
[a] => apple
[b] => banana
[sour] => lemon
)
Tôi cần phải biểu diễn mảng nhiều chiều của PHP ở định dạng đầu vào HTML.
$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"
}
$var['a']['b']['c'][0] = 'a'; ...
.
Nếu bạn có một mảng các đối tượng và muốn làm phẳng nó bằng một nút, chỉ cần sử dụng chức năng này:
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;
}