วิธีการทำให้อาเรย์หลายมิติเรียบ


259

เป็นไปได้ไหมใน PHP ที่จะขยายอาเรย์แบบสองมิติ (bi / multi) โดยไม่ต้องใช้การเรียกซ้ำหรือการอ้างอิง?

ฉันสนใจเฉพาะในค่าดังนั้นกุญแจสามารถปฏิเสธฉันคิดว่าในสายของและarray_map()array_values()


17
ทำไมหลีกเลี่ยงการเรียกซ้ำ?
JorenB

5
Dupe (ส่วนใหญ่) stackoverflow.com/questions/526556/…
cletus

4
คุณไม่สามารถทำอะไรกับองค์ประกอบทั้งหมดของอาร์เรย์ลึกโดยพลการโดยไม่มีการเรียกซ้ำ (คุณสามารถปลอมตัวเป็น iteration แต่ potato, potahto) หากคุณต้องการหลีกเลี่ยงการเขียนโค้ดการจัดการ recursion ด้วยตนเองให้ใช้dk2.php.net/ manual / en / function.array-walk-recursive.phpด้วยการเรียกกลับที่เพิ่มองค์ประกอบลงในอาร์เรย์ที่มีอยู่ (ใช้ global, พารามิเตอร์ userdata ใส่ไว้ในคลาสและอ้างอิง $ this, etc. )
Michael Madsen

@JorenB: ฉันต้องการที่จะเห็นการดำเนินการอาจถูกเก็บถาวร
Alix Axel

มีลักษณะที่เรียบฟังก์ชั่นจากNspl คุณยังสามารถระบุความลึกได้ด้วย
Ihor Burlachenko

คำตอบ:


276

คุณสามารถใช้ไลบรารี 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 

351
ฉันเป็นคนเดียวที่คิดว่า 'RecursiveIteratorIterator' เป็นชื่อที่โง่?
nilamo

45
มันเป็น "ตรรกะ" มากกว่า "ลวง" ทุกอย่างไม่สามารถมีชื่อที่ยอดเยี่ยมเช่น jogl, Knol หรือ Azure :-)
VolkerK

7
สิ่งนี้จะไม่ทำงานสำหรับอาร์เรย์ว่างเปล่าในขณะที่เด็ก พวกเขาจะถูกส่งคืนในฐานะผู้ปกครอง
hakre

45
iterator_to_array($it, false)หลีกเลี่ยงความต้องการ foreach
Alix Axel

3
จากสิ่งที่คนอื่นนำเสนอฉันสามารถสร้างผู้ช่วยตัวน้อยนี้ได้: function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }หวังว่านี่จะช่วยผู้อื่นได้
Mike S.

295

ในฐานะที่เป็นของPHP 5.3ทางออกที่สั้นที่สุดน่าจะเป็นarray_walk_recursive()กับไวยากรณ์การปิดใหม่:

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

33
หากคุณต้องการคีย์ฟังก์ชันจะเรียบ (array $ array) {$ return = array (); array_walk_recursive ($ array, ฟังก์ชั่น ($ a, $ b) ใช้ (& $ return) {$ return [$ b] = $ a;}); ผลตอบแทน $ ผลตอบแทน; }
Brendon-Van-Heyzen

คุณสามารถเขียนสิ่งนี้เพื่อใช้กับ php 5.2 ได้หรือไม่?
อเล็กซ์

2
@Alex โชคไม่ดีที่คุณต้องใช้useไวยากรณ์เพื่อทำให้งานนี้เสร็จสิ้นarray_walk_recursiveเนื่องจากจะไม่ยอมรับ$userdataพารามิเตอร์ที่เป็นทางเลือกโดยการอ้างอิง
Tim Seguine

1
ดูเหมือนว่าจะทำงานได้ดีสำหรับอาร์เรย์ดังกล่าว -> ideone.com/DsmApPแต่ไม่ใช่สำหรับอันนั้น -> ideone.com/5Kltva หรือเป็นฉัน
เซบาสเตียน Piskorski

2
@Sebastian Piskorski เป็นเพราะค่าของคุณกำลังถูกปฏิบัติเหมือนคีย์ดังนั้นทันทีที่คุณแนะนำคู่คีย์ => ค่าในอาร์เรย์ค่าอาร์เรย์ของคุณในตำแหน่งดัชนีแรกจะถือว่าเป็นคีย์ที่ไม่มีค่าและเนื่องจากคีย์มี จะไม่ซ้ำกันซึ่งมีสองปุ่มตรงกับค่าของคุณได้รับการเพิ่มไปยังคีย์เดียวกัน วิธีแก้ปัญหาง่าย ๆ คือการเรียงลำดับอาร์เรย์ก่อน นี่คือพฤติกรรมที่มีอยู่ใน PHP
Martyn Shutt

92

วิธีแก้ปัญหาสำหรับอาเรย์ 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


ขอบคุณคนแรกทำงานในอาร์เรย์ที่ฉันได้รับจาก PDO ซึ่งโซลูชันอื่นไม่ได้
JAL

7
นี่เป็นกลยุทธ์ที่ไม่ดี call_user_func_array('array_merge', [])(สังเกตว่าอาเรย์ที่ว่างเปล่า) ส่งคืนค่า null และทริกเกอร์ข้อผิดพลาดการเตือน php มันเป็นทางออกที่ลื่นถ้าคุณรู้ว่าอาเรย์ของคุณจะไม่ว่างเปล่า แต่นั่นไม่ใช่ข้อสันนิษฐานทั่วไปที่หลายคนสามารถทำได้
แพะ

OP ขอเฉพาะการแก้ปัญหาที่ไม่เกิดซ้ำ
Élektra

ว้าวแบนเด็ด 2d! แต่เพื่อป้องกันการแจ้งให้ทราบล่วงหน้าให้ใช้$result = $array ?call_user_func_array('array_merge', $array) : [];
Alexander Goncharov

เจ๋ง bruh แต่คุณไม่ได้โดยบังเอิญ array-deflatten เคาน์เตอร์ฟังก์ชั่น?
FantomX1

64

ใน 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);

1
สิ่งนี้ใช้ได้เฉพาะเมื่อทุกองค์ประกอบของอาร์เรย์เป็นอาร์เรย์ หากอาร์เรย์ประกอบด้วยชนิดผสมเช่นสเกลาร์จะเกิดข้อผิดพลาดขึ้น
Otheus

@Ousus นั่นเป็นเพราะวิธีการแก้ปัญหาข้างต้นไม่ได้ใช้การเรียกซ้ำ อย่างที่คุณพูดมันต้องใช้อาเรย์ของอาเรย์ แต่ในด้านบวกนี้ควรจะเร็วกว่าวิธีอื่น ๆ เนื่องจากไม่มีค่าใช้จ่ายเพิ่มเติมของการเรียกใช้ฟังก์ชัน
Joyce Babu

2
จะโยนข้อผิดพลาดถ้าอาเรย์ด้านนอกว่างเปล่าสามารถหลีกเลี่ยงได้ถ้ารวมกับอาเรย์ที่ว่างเปล่าarray_merge([], ...$a);
Mohamed Gharib

@MohamedGharib จับที่ดี
จอยซ์บาบู

ถ้าใช้เชื่อมโยงอาร์เรย์คุณสามารถตรวจสอบการแก้ปัญหานี้stackoverflow.com/questions/40663687/...
alex

24

หากต้องการแบนซ้ำโดยไม่มีการเรียกซ้ำ (ตามที่คุณขอ) คุณสามารถใช้สแต็กได้ โดยปกติคุณสามารถใส่สิ่งนี้ลงในฟังก์ชั่นของมันเอง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ที่ฉันคิดว่าเป็นความคิดที่ดี


+1 สำหรับฟังก์ชัน array_flatten ที่โดดเด่น ฉันต้องเพิ่มif(!empty($value)){$flat[] = $value}ในคำสั่ง else เพื่อป้องกันการเพิ่มว่างในอาร์เรย์ผลลัพธ์ ฟังก์ชั่นสุดยอด!
Alex Sarnowski

19

คำตอบที่ตรงไปตรงมาและหนึ่งซับ

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
Nigel Alderton

1
@NigelAlderton เพียงแค่เพิ่มfalseพารามิเตอร์ตัวที่สอง ( $use_keys) ลงในการiterator_to_arrayโทร
Svish

18

ใช้การเรียกซ้ำ หวังว่าเมื่อเห็นว่ามันไม่ซับซ้อนแค่ไหนความกลัวในการเรียกซ้ำของคุณจะหายไปเมื่อคุณเห็นว่ามันไม่ซับซ้อน

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>

1
ฉันไม่กลัวการเรียกซ้ำฉันแค่ต้องการเรียนรู้วิธีอื่นในการทำเช่นเดียวกัน
Alix Axel

13
+1 สำหรับการเรียกซ้ำครั้งนี้: หวังว่าเมื่อคุณเห็นว่ามันไม่ซับซ้อนแค่ไหนความกลัวในการเรียกซ้ำของคุณจะกระจายไปเมื่อคุณเห็นว่ามันไม่ซับซ้อนแค่ไหน
Tiberiu-Ionuț Stan

1
ตกลงนี่คือฉัน วิธีการก็เป็นไปได้ว่าการตอบกลับ ( "ฉันไม่กลัว recursion") เป็นสามและครึ่งปีเก่า (24 สิงหาคม 09) มากกว่าคำสั่งครั้งแรก ( "( ... ) ความกลัวของคุณ recursion จะกระจาย ( ... ) ") ทำเมื่อวันที่ 5 กุมภาพันธ์ 13
trejder

18

แค่คิดว่าฉันชี้ให้เห็นว่านี่เป็นแบบพับดังนั้น 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


หลายมิติ! = สองมิติ
Alix Axel

@atamur ใช้งานได้กับ PHP 5.3+ ตามที่ระบุไว้ในการเปลี่ยนแปลงสำหรับ array_reduce, $ เริ่มต้นเท่านั้นที่สามารถเป็นจำนวนเต็มก่อน 5.3 แล้วมันได้รับอนุญาตให้เป็น "ผสม" (คืออะไรของคุณฟังก์ชั่นการลดการสนับสนุน.)
Warbo

1
@AlixAxel คุณพูดถูกแล้วว่าหลายมิติ! = สองมิติ แต่สิ่งนี้สามารถทำให้เรียบได้หลายระดับ สิ่งที่ดีอย่างหนึ่งในการเขียนโฟลด์คือมันเชื่อฟังขีด จำกัด คงที่; ถ้าฉันมีอาร์เรย์ซ้อนกันถึง 5 ระดับฉันสามารถfoldแบ่งออกเป็น 4 ระดับหรือเพิ่มfold . foldเป็น 3 ระดับหรือเพิ่มfold . fold . foldเป็น 2 ระดับเป็นต้นซึ่งจะช่วยป้องกันข้อผิดพลาดที่ซ่อนอยู่ เช่น. ถ้าฉันต้องการที่จะแบนอาร์เรย์ 5D แต่ฉันได้รับอาร์เรย์ 4D ข้อผิดพลาดจะทริกเกอร์ทันที
Warbo

ฉันชอบวิธีนี้สำหรับอาร์เรย์ 2 มิติ เหมาะกับการเรียกเก็บเงินอย่างสมบูรณ์แบบ
Tom Auger

ฉันเห็นด้วยว่าคำจำกัดความระดับเดียวของคุณคือคำตอบที่ดีที่สุดมันก็เยี่ยมยอดมาก แต่ฉันคิดว่าคุณตั้งชื่อมันไม่ถูกต้องผมคิดว่าคุณก็ควรจะเรียกมันว่า$concat เท่ากับ php ของ concat ฉันพยายามที่จะได้รับเพิ่มเป็นนามแฝงสำหรับ $flattenarray_mergearray_concatarray_merge
icc97

9

แผ่อาร์เรย์สองมิติเท่านั้น:

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

// Result: [1, 2, 3, 4]

5

โซลูชันนี้ไม่เรียกซ้ำ โปรดทราบว่าลำดับขององค์ประกอบจะค่อนข้างผสมกัน

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

1
ความคิดที่ฉลาด แต่มีข้อบกพร่อง "$ array [] = $ value" ไม่ได้เพิ่มองค์ประกอบทั้งหมดของ $ value ไปยัง $ array แต่เพิ่มเพียง $ value เท่านั้น หากคุณเรียกใช้รหัสนี้มันจะวนซ้ำอย่างไม่มีกำหนด
ทอดด์โอเว่น

ใช่shiftingค่าจากอาร์เรย์และต่อท้ายอีกครั้งจะไม่สมเหตุสมผล ฉันคิดว่าคุณต้องการที่จะarray_merge()แทน?
หลอกลวง

4

ฉันเชื่อว่านี่เป็นคำตอบที่สะอาดที่สุดโดยไม่ต้องใช้การกลายพันธุ์หรือคลาสที่ไม่คุ้นเคย

<?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));

3

ลองใช้ฟังก์ชั่นง่าย ๆ ดังต่อไปนี้:

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',
)

บางทีคุณควรตรวจสอบฟังก์ชั่นของคุณ ... ดูเหมือนว่าจะไม่ทำงานอย่างที่คาดไว้
Emiliano

@Emiliano ลองถามคำถามใหม่บางทีข้อมูลอินพุตของคุณอาจแตกต่างออกไปดังนั้นมันจะไม่ทำงานในกรณีเฉพาะของคุณ
kenorb

เรามีปัญหาเล็กน้อยแต่ละข้อเป็นฟังก์ชั่นที่เลิกใช้แล้วคุณสามารถปรับปรุงจุดที่คุณไม่ใช่คนใหม่ที่นี่คุณควรรู้ว่าสองหากรหัสของคุณทำงานกับ php รุ่นเฉพาะบอกว่าสามถ้าไม่ทำงานกับข้อมูลทั้งหมดบอกว่ามัน
Emiliano

2

เคล็ดลับคือการส่งผ่านทั้งอาร์เรย์ต้นทางและปลายทางโดยการอ้างอิง

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);

2
/**
 * 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));
    }
);

สรุปสาระสำคัญ


ดูเหมือนว่าจะรองรับเฉพาะอาร์เรย์สองมิติเท่านั้น
Alix Axel

คุณพูดถูก ไม่มีประโยชน์ที่จะใช้ ฉันคิดว่าทางออกที่ดีที่สุดคือคำตอบ "มากเกินไป php"
Arsham


2

หากคุณไม่ชอบการสอบถามซ้ำลองเปลี่ยนเป็นแทน :)

$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];
    }
}

หมายเหตุ:ในเวอร์ชั่นง่าย ๆ นี้ไม่รองรับคีย์อาเรย์


นี่เป็นวิธีการที่น่าสนใจ ตรงกันข้ามกับโซลูชันอื่น ๆ มันจะแก้ไขอาร์เรย์ดั้งเดิม ($ a) หากคุณแทนที่ด้วย a continueมันจะค่อนข้างเร็วกว่า
pcarvalho

2

วิธีการเกี่ยวกับการใช้เครื่องกำเนิดไฟฟ้าแบบเรียกซ้ำ? 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;
        }
    }
}

1

สำหรับ 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;
}

โปรดระบุคำอธิบายด้วยคำตอบสำหรับรหัสนี้เท่านั้น
mickmackusa

1

รุ่นนี้สามารถทำลึกตื้นหรือจำนวนเฉพาะระดับ:

/**
 * @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;
}

นอกเหนือจากการอธิบายว่าข้อมูลนี้สามารถทำอะไรได้บ้างโปรดอธิบายให้นักวิจัยในอนาคตทราบว่ามันทำงานอย่างไร
mickmackusa

1

เพราะรหัสในที่นี่ดูน่ากลัว นี่คือฟังก์ชั่นที่จะแปลงอาเรย์หลายมิติเป็นรูปแบบที่เข้ากันได้กับรูปแบบ 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;
}


0

นี่คือทางออกของฉันโดยใช้การอ้างอิง:

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>";

โปรดระบุคำอธิบายว่าข้อมูลโค้ดของคุณทำงานอย่างไรและทำไมจึงเป็นความคิดที่ดี คำตอบที่ใช้รหัสเท่านั้นมีค่าต่ำใน StackOverflow เพราะพวกเขาทำงานได้ไม่ดีในการให้ความรู้ / เสริมสร้างศักยภาพของ OP และนักวิจัยในอนาคต จำไว้ว่าเราไม่เคยพูดกับ OP เท่านั้น หน้าเก่าจะใช้ในการปิดหน้าใหม่ดังนั้นหน้าจำเป็นต้องมีข้อมูลเพียงพอที่จะแก้ปัญหาสำหรับผู้ถามในอนาคตเช่นกัน
mickmackusa

0
<?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;
}
?>

0

นี่เป็นวิธีง่าย ๆ :

$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);

0

ใครก็ตามที่กำลังมองหาทางออกที่สะอาดจริงๆ นี่คือตัวเลือก:

$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

0

เพียงโพสต์โซลูชันอื่น)

function flatMultidimensionalArray(array &$_arr): array
{
    $result = [];
    \array_walk_recursive($_arr, static function (&$value, &$key) use (&$result) {
        $result[$key] = $value;
    });

    return $result;
}

0

หากคุณต้องการเก็บกุญแจของคุณไว้ด้วยเช่นกัน

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
)

-1

ฉันต้องการแสดงอาร์เรย์ 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"
}


@AlixAxel ความคิดเห็นนี้สัมพันธ์กันอย่างไร โพสต์ผิด ..
Gajus

ครั้งที่ผมคิดว่ามันสวยคล้ายกับสิ่งที่คุณทำและตัดสินใจที่จะร่วมกันผมคิดว่าแตกต่างเพียงว่าเป็นตัวแทนของฉันถูกต้อง PHP เป็นอย่างดี - $var['a']['b']['c'][0] = 'a'; ...ของแบบฟอร์ม
Alix Axel

ฉันต้องการเอาต์พุต HTML โดยเจตนา แม้ว่าขอบคุณสำหรับการแบ่งปัน
Gajus

1
ฉันรู้สึกว่านี่เป็นคำตอบที่ถูกสำหรับคำถามที่ผิด เมื่อตอบโปรดพยายามตอบคำถามตามที่ถามมิฉะนั้นหน้าเว็บอาจหลุดจากประเด็นหลักและทำให้นักวิจัยในอนาคตสับสน
mickmackusa

-1

หากคุณมีอาเรย์ของวัตถุและต้องการทำให้แบนด้วยโหนดเพียงแค่ใช้ฟังก์ชั่นนี้:

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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.