Làm thế nào để làm phẳng một mảng nhiều chiều?


259

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()array_values().


17
Tại sao tránh đệ quy?
JorenB


4
Bạn không thể làm bất cứ điều gì với tất cả các yếu tố của một mảng sâu tùy ý mà không cần đệ quy (bạn có thể ngụy trang nó thành phép lặp, nhưng khoai tây, potahto.) Nếu bạn chỉ muốn tránh tự viết mã xử lý đệ quy, hãy sử dụng dk2.php.net/ hướng dẫn sử dụng / en / function.array-walk-recursive.php với một cuộc gọi lại thêm phần tử vào một mảng có sẵn (sử dụng toàn cầu, tham số userdata, đặt tất cả trong một lớp và tham khảo $ this, v.v.)
Michael Madsen

@JorenB: Tôi muốn thấy một triển khai có thể được lưu trữ.
Alix Axel

Có một cái nhìn về chức năng làm phẳng từ Nspl . Bạn cũng có thể chỉ định một độ sâu với nó.
Ihor Burlachenko

Câu trả lời:


276

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 

351
Tôi có phải là người duy nhất nghĩ rằng 'RecursiveIteratorIterator' là một cái tên ngớ ngẩn không?
nilamo

45
Nó "hợp lý" hơn "hấp dẫn". Không phải tất cả mọi thứ đều có thể có một cái tên tuyệt vời như JOGL, Knol hoặc Azure :-)
VolkerK

7
Điều này sẽ không làm việc cho các mảng trống khi trẻ em. Họ sẽ được trả lại như một phụ huynh.
hakre

45
iterator_to_array($it, false)tránh sự cần thiết cho các foreach.
Alix Axel

3
Dựa trên những gì người khác trình bày, tôi đã có thể tạo ra người trợ giúp nhỏ này: 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.
Mike S.

295

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

33
nếu bạn muốn khóa, hàm flatten (mảng $ mảng) {$ return = mảng (); mảng_walk_recursive ($ mảng, hàm ($ a, $ b) sử dụng (& $ return) {$ return [$ b] = $ a;}); trả lại $ trả lại; }
Brendon-Van-Heyzen

bạn có thể viết lại cái này để sử dụng với php 5.2 không?
Alex

2
@Alex thật không may, bạn cần usecú pháp để thực hiện công việc này array_walk_recursivevì nó sẽ không chấp nhận $userdatatham số tùy chọn theo tham chiếu
Tim Seguine

1
Trông giống như hoạt động tốt cho Mảng như vậy -> ideone.com/DsmApP Nhưng không phải cho những cái như vậy -> ideone.com/5Kltva Hay là tôi?
Sebastian Piskorski

2
@Sebastian Piskorski là do các giá trị của bạn đang được xử lý như các khóa, vì vậy ngay khi bạn giới thiệu cặp khóa => giá trị của riêng bạn trong một mảng, các giá trị mảng của bạn ở vị trí chỉ mục đầu tiên được coi như các khóa không có giá trị và vì các khóa có là duy nhất, trong đó hai khóa khớp nhau, các giá trị của bạn sẽ được thêm vào cùng một khóa. Một giải pháp đơn giản sẽ là sắp xếp mảng trước. Đây là hành vi vốn có trong PHP.
Martyn Shutt

92

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


Cảm ơn bạn, người đầu tiên đã làm việc trên một mảng mà tôi đã nhận được từ PDO nơi mà các giải pháp khác không có.
JAL

7
Đây là một chiến lược kém. 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.

OP đặc biệt yêu cầu các giải pháp không đệ quy.
Élektra

Wow, mô hình 2d mát mẻ! Nhưng để ngăn chặn thông báo chỉ cần sử dụng$result = $array ?call_user_func_array('array_merge', $array) : [];
Alexander Goncharov

tuyệt vời, nhưng bạn không có cơ hội một mảng phản ứng-deflatten?
FantomX1

64

Trong PHP 5.6 trở lên, bạn có thể làm phẳng các mảng hai chiều array_mergesau 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_valuestrướ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_mergesẽ đượ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);

1
Điều này chỉ hoạt động khi mọi phần tử của mảng là một mảng. Nếu mảng bao gồm các loại hỗn hợp, chẳng hạn như vô hướng, sẽ xảy ra lỗi.
Otheus

@Otheus Đó là vì giải pháp trên không sử dụng đệ quy. Như bạn đã nói, nó đòi hỏi một mảng của mảng. Nhưng về mặt tích cực, điều này sẽ nhanh hơn nhiều so với các phương thức khác, vì nó không có chi phí bổ sung của các lệnh gọi hàm.
Joyce Babu

2
Sẽ xuất hiện lỗi nếu mảng bên ngoài trống, có thể tránh được nếu kết hợp với mảng trốngarray_merge([], ...$a);
Mohamed Gharib

@MohamedGharib Bắt đẹp.
Joyce Babu

Nếu sử dụng mảng kết hợp, bạn có thể kiểm tra giải pháp này stackoverflow.com/questions
40663687 / Giả

24

Để 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 RecurisiveIteratorsử 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";
}

Bản giới thiệu

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.


+1 cho hàm Array_flatten nổi bật. Tôi đã phải thêm 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!
Alex Sarnowski

19

Câu trả lời đơn giảnmộ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ành Array ([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


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

1
@NigelAlderton Chỉ cần thêm falsedưới dạng tham số thứ hai ( $use_keys) vào iterator_to_arraycuộc gọi.
Svish

18

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>

1
Tôi không sợ đệ quy, tôi chỉ muốn học những cách khác để làm điều tương tự.
Alix Axel

13
+1 cho đệ quy này: Hy vọng khi thấy nó không phức tạp, 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.
Tiberiu-Ionuț Stan

1
OK, đây là hơn tôi. Làm thế nào có thể, câu trả lời đó ("Tôi không sợ đệ quy") lớn hơn ba tuổi rưỡi (24 tháng 8 năm 2009) so với tuyên bố ban đầu ("(...) nỗi sợ đệ quy của bạn sẽ tan biến (... ) "), được thực hiện vào ngày 5 tháng 2 năm 13?
trejder

18

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.


Đa chiều! = Hai chiều.
Alix Axel

@atamur Điều này hoạt động trên PHP 5.3+. Như đã lưu ý trong thay đổi cho mảng_reduce, $ ban đầu chỉ có thể là một số nguyên trước 5.3, sau đó nó được phép "trộn" (nghĩa là mọi thứ mà hàm giảm của bạn hỗ trợ)
Warbo

1
@AlixAxel Bạn nói đúng là đa chiều! = Hai chiều, nhưng điều này có thể được tạo ra để làm phẳng bất kỳ số cấp nào. Một kết quả tốt đẹp của việc soạn các nếp gấp là nó tuân theo một giới hạn cố định; Nếu tôi có một mảng được lồng vào 5 cấp độ, tôi có thể foldchia 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.
Warbo

Tôi thích giải pháp này, cho mảng 2 chiều. Phù hợp với hóa đơn hoàn hảo.
Tom Auger

Tôi đồng ý rằng định nghĩa cấp độ duy nhất của bạn là câu trả lời tốt nhất, nó cũng tuyệt vời gọn gàng. Tuy nhiên tôi nghĩ bạn đặt tên không chính xác $concat, tôi nghĩ bạn chỉ nên gọi nó $flatten. array_mergelà tương đương php của concat. Tôi đã cố gắng để được array_concatthêm vào như một bí danh cho array_merge.
icc97

9

Làm phẳng các mảng hai chiều:

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

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

5

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

1
Ý tưởng thông minh, nhưng có một lỗi. "$ mảng [] = $ value" không thêm tất cả các phần tử của giá trị $ vào mảng $, nó chỉ thêm chính giá trị $. Nếu bạn chạy mã này, nó sẽ lặp vô hạn.
Todd Owen

Có, shiftinggiá 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ế?
lừa dối

4

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

3

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

có lẽ bạn nên kiểm tra chức năng của mình ... có vẻ như không có công việc như mong đợi
Emiliano

@Emiliano Hãy thử hỏi một câu hỏi mới, có thể dữ liệu đầu vào của bạn khác, vì vậy nó sẽ không hoạt động trong trường hợp cụ thể của bạn.
kenorb

Chúng tôi có một số vấn đề, mỗi vấn đề là một hàm không dùng nữa, bạn có thể cải thiện điểm đó bạn không phải là người mới ở đây, bạn nên biết thứ hai nếu mã của bạn hoạt động với một phiên bản cụ thể của php nói nó thứ ba nếu không hoạt động với tất cả dữ liệu.
Emiliano

2

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

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

Đoạn trích


Điều này dường như chỉ hỗ trợ mảng hai chiều.
Alix Axel

Bạn đúng rồi. Không có điểm để sử dụng nó. Tôi nghĩ rằng giải pháp tốt nhất là câu trả lời của "quá nhiều php".
Arsham


2

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.


đây là một cách tiếp cận thú vị ngược lại với các giải pháp khác, nó chỉnh sửa mảng ban đầu ($ a). Nếu bạn thay thế nó bằng một continue, nó có phần nhanh hơn.
pcarvalho

2

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

1

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

Vui lòng bao gồm một số giải thích với câu trả lời chỉ có mã này.
mickmackusa

1

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

Ngoài việc giải thích những gì đoạn trích này có thể làm, hãy giải thích cho các nhà nghiên cứu trong tương lai về cách thức hoạt động của nó.
mickmackusa

1

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

1

Đ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


0

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

Vui lòng bao gồm một số giải thích về cách hoạt động của đoạn trích của bạn và lý do tại sao đó là một ý tưởng tốt. Các câu trả lời chỉ có mã là giá trị thấp trên StackOverflow vì chúng làm rất kém trong việc giáo dục / trao quyền cho OP và các nhà nghiên cứu trong tương lai. Hãy nhớ rằng, chúng tôi không bao giờ CHỈ nói với OP; các trang cũ được sử dụng để đóng các trang mới, vì vậy các trang cần phải đủ thông tin để giải quyết các vấn đề cho người hỏi trong tương lai.
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

Đây là một cách tiếp cận đơn giản:

$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

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

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

0

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
)

-1

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


@AlixAxel Nhận xét này có liên quan như thế nào? Sai bài ..?
Gajus

Không. Tôi nghĩ nó khá giống với những gì bạn đang làm và quyết định chia sẻ nó, tôi nghĩ sự khác biệt duy nhất là đại diện của tôi cũng là PHP hợp lệ - về hình thức $var['a']['b']['c'][0] = 'a'; ....
Alix Axel

Tôi cố tình cần đầu ra HTML. Mặc dù cảm ơn bạn đã chia sẻ.
Gajus

1
Tôi cảm thấy rằng đây là câu trả lời đúng cho câu hỏi sai. Khi trả lời, vui lòng cố gắng trả lời câu hỏi khi được hỏi - nếu không các trang có thể rời khỏi vấn đề cốt lõi và khiến các nhà nghiên cứu trong tương lai bối rối.
mickmackusa

-1

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.