เป็นไปได้ไหมใน PHP ที่จะขยายอาเรย์แบบสองมิติ (bi / multi) โดยไม่ต้องใช้การเรียกซ้ำหรือการอ้างอิง?
ฉันสนใจเฉพาะในค่าดังนั้นกุญแจสามารถปฏิเสธฉันคิดว่าในสายของและarray_map()
array_values()
เป็นไปได้ไหมใน PHP ที่จะขยายอาเรย์แบบสองมิติ (bi / multi) โดยไม่ต้องใช้การเรียกซ้ำหรือการอ้างอิง?
ฉันสนใจเฉพาะในค่าดังนั้นกุญแจสามารถปฏิเสธฉันคิดว่าในสายของและarray_map()
array_values()
คำตอบ:
คุณสามารถใช้ไลบรารี PHP มาตรฐาน (SPL)เพื่อ "ซ่อน" การสอบถามซ้ำ
$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
iterator_to_array($it, false)
หลีกเลี่ยงความต้องการ foreach
function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }
หวังว่านี่จะช่วยผู้อื่นได้
ในฐานะที่เป็นของPHP 5.3ทางออกที่สั้นที่สุดน่าจะเป็นarray_walk_recursive()
กับไวยากรณ์การปิดใหม่:
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
use
ไวยากรณ์เพื่อทำให้งานนี้เสร็จสิ้นarray_walk_recursive
เนื่องจากจะไม่ยอมรับ$userdata
พารามิเตอร์ที่เป็นทางเลือกโดยการอ้างอิง
วิธีแก้ปัญหาสำหรับอาเรย์ 2 มิติ
กรุณาลองสิ่งนี้:
$array = your array
$result = call_user_func_array('array_merge', $array);
echo "<pre>";
print_r($result);
แก้ไข: 21-Aug-13
นี่คือโซลูชันที่ใช้งานได้สำหรับอาร์เรย์หลายมิติ:
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);
Ref: http://php.net/manual/th/function.call-user-func-array.php
call_user_func_array('array_merge', [])
(สังเกตว่าอาเรย์ที่ว่างเปล่า) ส่งคืนค่า null และทริกเกอร์ข้อผิดพลาดการเตือน php มันเป็นทางออกที่ลื่นถ้าคุณรู้ว่าอาเรย์ของคุณจะไม่ว่างเปล่า แต่นั่นไม่ใช่ข้อสันนิษฐานทั่วไปที่หลายคนสามารถทำได้
$result = $array ?call_user_func_array('array_merge', $array) : [];
ใน PHP 5.6 และสูงกว่าคุณสามารถแบนอาร์เรย์สองมิติด้วยarray_merge
หลังจากเอาอาร์เรย์ด้านนอกออกด้วย...
ตัวดำเนินการ รหัสนั้นง่ายและชัดเจน
array_merge(...$a);
ใช้ได้กับคอลเลกชันของอาร์เรย์ที่เชื่อมโยงด้วย
$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
)
อัปเดต: อิงตามความคิดเห็นโดย @MohamedGharib
สิ่งนี้จะทำให้เกิดข้อผิดพลาดถ้าอาเรย์ด้านนอกว่างเปล่าเนื่องจากarray_merge
จะถูกเรียกด้วยอาร์กิวเมนต์ที่ไม่มีค่า สามารถหลีกเลี่ยงได้โดยการเพิ่มอาร์เรย์ว่างเป็นอาร์กิวเมนต์แรก
array_merge([], ...$a);
array_merge([], ...$a);
หากต้องการแบนซ้ำโดยไม่มีการเรียกซ้ำ (ตามที่คุณขอ) คุณสามารถใช้สแต็กได้ โดยปกติคุณสามารถใส่สิ่งนี้ลงในฟังก์ชั่นของมันเองarray_flatten
ได้ ต่อไปนี้เป็นรุ่นที่ทำงานโดยไม่มีปุ่ม:
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 เดินผ่านอาร์เรย์หลายมิติในขณะที่เก็บกุญแจ
ฉันไม่แน่ใจโดยเฉพาะ แต่ II ได้ทดสอบสิ่งนี้ในอดีต: การRecurisiveIterator
ใช้การสอบถามซ้ำจึงขึ้นอยู่กับสิ่งที่คุณต้องการจริงๆ ควรเป็นไปได้ในการสร้างตัววนซ้ำแบบวนซ้ำตามสแต็กเช่นกัน:
foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
echo "** ($key) $value\n";
}
ฉันไม่ได้ทำจนถึงตอนนี้เพื่อใช้สแต็กตามRecursiveIterator
ที่ฉันคิดว่าเป็นความคิดที่ดี
if(!empty($value)){$flat[] = $value}
ในคำสั่ง else เพื่อป้องกันการเพิ่มว่างในอาร์เรย์ผลลัพธ์ ฟังก์ชั่นสุดยอด!
คำตอบที่ตรงไปตรงมาและหนึ่งซับ
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)
เธซเธฑไนเจล Alderton 's กังวลปัญหา /:
เพียงชี้แจงนี้จะเก็บรักษากุญแจ (แม้กระทั่งตัวเลข) ดังนั้นค่าที่มีคีย์เดียวกันจะหายไป ยกตัวอย่างเช่นจะกลายเป็น
$array = ['a',['b','c']]
Array ([0] => b, [1] => c )
การ'a'
สูญหายเพราะ'b'
ยังมีกุญแจ0
การตอบคำตอบของSvish :
เพียงเพิ่ม false เป็นพารามิเตอร์ที่สอง
($use_keys)
ในการเรียกiterator_to_array
$array = ['a',['b','c']]
จะหายไปเพราะยังมีที่สำคัญของ Array ([0] => b, [1] => c )
'a'
'b'
0
ใช้การเรียกซ้ำ หวังว่าเมื่อเห็นว่ามันไม่ซับซ้อนแค่ไหนความกลัวในการเรียกซ้ำของคุณจะหายไปเมื่อคุณเห็นว่ามันไม่ซับซ้อน
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
fold
แบ่งออกเป็น 4 ระดับหรือเพิ่มfold . fold
เป็น 3 ระดับหรือเพิ่มfold . fold . fold
เป็น 2 ระดับเป็นต้นซึ่งจะช่วยป้องกันข้อผิดพลาดที่ซ่อนอยู่ เช่น. ถ้าฉันต้องการที่จะแบนอาร์เรย์ 5D แต่ฉันได้รับอาร์เรย์ 4D ข้อผิดพลาดจะทริกเกอร์ทันที
แผ่อาร์เรย์สองมิติเท่านั้น:
$arr = [1, 2, [3, 4]];
$arr = array_reduce($arr, function ($a, $b) {
return array_merge($a, (array) $b);
}, []);
// Result: [1, 2, 3, 4]
โซลูชันนี้ไม่เรียกซ้ำ โปรดทราบว่าลำดับขององค์ประกอบจะค่อนข้างผสมกัน
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
ค่าจากอาร์เรย์และต่อท้ายอีกครั้งจะไม่สมเหตุสมผล ฉันคิดว่าคุณต้องการที่จะarray_merge()
แทน?
ฉันเชื่อว่านี่เป็นคำตอบที่สะอาดที่สุดโดยไม่ต้องใช้การกลายพันธุ์หรือคลาสที่ไม่คุ้นเคย
<?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));
ลองใช้ฟังก์ชั่นง่าย ๆ ดังต่อไปนี้:
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',
)
เคล็ดลับคือการส่งผ่านทั้งอาร์เรย์ต้นทางและปลายทางโดยการอ้างอิง
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));
}
);
หากคุณไม่ชอบการสอบถามซ้ำลองเปลี่ยนเป็นแทน :)
$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];
}
}
หมายเหตุ:ในเวอร์ชั่นง่าย ๆ นี้ไม่รองรับคีย์อาเรย์
continue
มันจะค่อนข้างเร็วกว่า
วิธีการเกี่ยวกับการใช้เครื่องกำเนิดไฟฟ้าแบบเรียกซ้ำ? 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;
}
}
}
สำหรับ 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;
}
เพราะรหัสในที่นี่ดูน่ากลัว นี่คือฟังก์ชั่นที่จะแปลงอาเรย์หลายมิติเป็นรูปแบบที่เข้ากันได้กับรูปแบบ 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;
}
สามารถทำได้โดยใช้ 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);
ตัวอย่างการทำงาน: - https://3v4l.org/FpIrG
นี่คือทางออกของฉันโดยใช้การอ้างอิง:
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;
}
?>
นี่เป็นวิธีง่าย ๆ :
$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);
ใครก็ตามที่กำลังมองหาทางออกที่สะอาดจริงๆ นี่คือตัวเลือก:
$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) ) ;
พิมพ์
0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0
เพียงโพสต์โซลูชันอื่น)
function flatMultidimensionalArray(array &$_arr): array
{
$result = [];
\array_walk_recursive($_arr, static function (&$value, &$key) use (&$result) {
$result[$key] = $value;
});
return $result;
}
หากคุณต้องการเก็บกุญแจของคุณไว้ด้วยเช่นกัน
function reduce(array $array) {
$return = array();
array_walk_recursive($array, function($value, $key) use (&$return) { $return[$key] = $value; });
return $return;
}
น่าเสียดายที่มันส่งออกเฉพาะอาร์เรย์ที่ซ้อนกันสุดท้ายโดยไม่มีคีย์กลาง ดังนั้นสำหรับตัวอย่างต่อไปนี้:
$array = array(
'sweet' => array(
'a' => 'apple',
'b' => 'banana'),
'sour' => 'lemon');
print_r(flatten($fruits));
ผลลัพธ์คือ:
Array
(
[a] => apple
[b] => banana
[sour] => lemon
)
ฉันต้องการแสดงอาร์เรย์ PHP หลายมิติในรูปแบบอินพุต 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'; ...
ของแบบฟอร์ม
หากคุณมีอาเรย์ของวัตถุและต้องการทำให้แบนด้วยโหนดเพียงแค่ใช้ฟังก์ชั่นนี้:
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;
}