Làm thế nào để "san phẳng" một mảng đa chiều thành một mảng đơn giản trong PHP?


83

Đây có lẽ là câu hỏi dành cho người mới bắt đầu nhưng tôi đang xem qua tài liệu trong thời gian dài hơn và tôi không thể tìm thấy giải pháp nào. Tôi nghĩ rằng tôi có thể sử dụng mã hóa cho mỗi chiều và sau đó đặt các chuỗi đó lại với nhau str_splitđể tạo mảng đơn giản mới. Tuy nhiên, tôi không bao giờ biết nếu mẫu nối cũng không có trong các giá trị và vì vậy sau khi thực hiện, str_splitcác giá trị ban đầu của tôi có thể bị phá vỡ.

Có một cái gì đó giống như combine($array1, $array2)cho các mảng bên trong của mảng đa chiều?


Vui lòng kiểm tra liên kết này để biết giải pháp : stackoverflow.com/questions/14951811/…
Prasanth Bendra

1
Một câu hỏi tham khảo tốt khác có câu trả lời có lẽ tốt hơn: Làm thế nào để làm phẳng một mảng đa chiều?
hakre

Câu trả lời:


42

Sử dụng array_walk_recursive

<?php

$aNonFlat = array(
    1,
    2,
    array(
        3,
        4,
        5,
        array(
            6,
            7
        ),
        8,
        9,
    ),
    10,
    11
);

$objTmp = (object) array('aFlat' => array());

array_walk_recursive($aNonFlat, create_function('&$v, $k, &$t', '$t->aFlat[] = $v;'), $objTmp);

var_dump($objTmp->aFlat);

/*
array(11) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
  [5]=>
  int(6)
  [6]=>
  int(7)
  [7]=>
  int(8)
  [8]=>
  int(9)
  [9]=>
  int(10)
  [10]=>
  int(11)
}
*/

?>

Đã thử nghiệm với PHP 5.5.9-1ubuntu4.24 (cli) (xây dựng: 16/03/2018 12:32:06)


Có ai biết tại sao điều này không hoạt động trừ khi tôi sử dụng thời gian gọi (đã khấu hao) theo tham chiếu. tức là array_walk_recursive ($ array, create_ functions ('& $ v, $ k, & $ t', '$ t [] = $ v;'), & $ fl flat); Định nghĩa hàm được xác định chính xác là truyền qua tham chiếu. nhưng không hoạt động trừ khi tôi chuyển qua tham chiếu trong thời gian gọi.
jskulski

2
@jskilski Đối tượng ( $objTmptrong ví dụ này) được chuyển tự động bằng tham chiếu; mảng không. Hãy thử sử dụng một hàm ẩn danh ( php.net/manual/en/functions.anonymous.php ) thay vì create_function.
dave1010

1
doesnt làm việc này trong php 5.3.3 do một lỗi trong array_walk_recursive - bugs.php.net/bug.php?id=52719
crazyphoton

1
@crazyphoton Các xoắn cũng nóiThis bug has been fixed in SVN.
Luc M

10
Tại sao câu trả lời này lại đề cập đến việc sử dụng array_values()? Tôi không thể thấy bất kỳ việc sử dụng nào của chức năng đó liên quan đến câu trả lời.
thomasrutter

131
$array  = your array

$result = call_user_func_array('array_merge', $array);

echo "<pre>";
print_r($result);

REF: http://php.net/manual/en/ Chức năng.call-user-func- array.php

Đây là một giải pháp khác (hoạt động với 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);

Câu trả lời này nhanh hơn nhiều so với câu trả lời được chấp nhận.
Roham Rafii

8
Kể từ PHP5.3 bây giờ bạn có thể sử dụng toán tử splat: $result = array_merge(...$array); php.net/manual/en/...
Redzarf

1
Câu trả lời đầu tiên của bạn không hoạt động với một mảng nhiều chiều. 3v4l.org/tY8vD
dearsina

54

Đây là một dòng, SIÊU dễ sử dụng:

$result = array();
array_walk_recursive($original_array,function($v) use (&$result){ $result[] = $v; });

Nó rất dễ hiểu, bên trong hàm ẩn danh / đóng cửa. $vlà giá trị của bạn $original_array.


4
Đây là cái duy nhất làm việc cho tôi trong mảng hai cấp.
Ciprian Tepes

18
// $array = your multidimensional array

$flat_array = array();

foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v){

$flat_array[$k] = $v;

}

Cũng được tài liệu: http://www.phpro.org/examples/Flatten-Array.html


2
Lưu ý: Chỉ sử dụng cho các mảng nguyên thủy. "RecursiveArrayIterator coi tất cả các đối tượng là có con và cố gắng đệ quy lại chúng." php.net/manual/en/class.recursivearrayiterator.php#106519
ReactiveRaven

@hakre: +1 đồng ý: thêm iterator_to_array() vào câu trả lời này sẽ phủ nhận sự cần thiết của foreachvòng lặp. Nó có thể là một hàm một lớp đơn giản. (mặc dù một dòng hơi dài)
SDC

2
Tôi biết điều này đã cũ nhưng vẫn hữu ích, tuy nhiên $ k cần được thay thế bằng thứ gì đó độc đáo, chẳng hạn như bộ đếm. Chỉ cần sử dụng $ k sẽ khiến các phần tử bị xóa nếu tên giống nhau trong các mảng bên trong như mảng chính.
Austin Best

12

Nếu bạn đặc biệt có một mảng các mảng không sâu hơn một cấp (một trường hợp sử dụng mà tôi thấy phổ biến), bạn có thể bỏ qua array_mergevà toán tử splat.

<?php

$notFlat = [[1,2],[3,4]];
$flat = array_merge(...$notFlat);
var_dump($flat);

Đầu ra:

array(4) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
}

Toán tử splat thay đổi hiệu quả mảng mảng thành danh sách mảng làm đối số array_merge.


Đây có vẻ là câu trả lời tốt nhất đối với tôi. Nó sẽ không hoạt động với các phím chuỗi, nhưng có thể dễ dàng sửa đổi để làm như vậy:$flat = array_merge( array_keys( $notFlat ), ...array_values( $notFlat ) );
Ian Dunn

6

Với PHP 7, bạn có thể sử dụng trình tạo và ủy quyền trình tạo ( yield from) để làm phẳng một mảng:

function array_flatten_iterator (array $array) {
    foreach ($array as $value) {
        if (is_array($value)) {
            yield from array_flatten_iterator($value);
        } else {
            yield $value;
        }
    }
}

function array_flatten (array $array) {
    return iterator_to_array(array_flatten_iterator($array), false);
}

Thí dụ:

$array = [
    1,
    2,
    [
        3,
        4,
        5,
        [
            6,
            7
        ],
        8,
        9,
    ],
    10,
    11,
];    

var_dump(array_flatten($array));

http://3v4l.org/RU30W


5
function flatten_array($array, $preserve_keys = 0, &$out = array()) {
    # Flatten a multidimensional array to one dimension, optionally preserving keys.
    #
    # $array - the array to flatten
    # $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
    # $out - internal use argument for recursion
    foreach($array as $key => $child)
        if(is_array($child))
            $out = flatten_array($child, $preserve_keys, $out);
        elseif($preserve_keys + is_string($key) > 1)
            $out[$key] = $child;
        else
            $out[] = $child;
    return $out;
}

Xin lỗi nhưng nó dường như không xử lý mảng đa chiều đúng cách - Demo
Álvaro González

5

Một phương pháp khác từ nhận xét của người dùng PHP (đơn giản hóa) và đây :

function array_flatten_recursive($array) { 
   if (!$array) return false;
   $flat = array();
   $RII = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
   foreach ($RII as $value) $flat[] = $value;
   return $flat;
}

Lợi ích lớn của phương pháp này là nó theo dõi độ sâu của đệ quy, nếu bạn cần điều đó trong khi làm phẳng.
Điều này sẽ xuất ra:

$array = array( 
    'A' => array('B' => array( 1, 2, 3)), 
    'C' => array(4, 5) 
); 
print_r(array_flatten_recursive($array)); 

#Returns: 
Array ( 
    [0] => 1 
    [1] => 2 
    [2] => 3 
    [3] => 4 
    [4] => 5 
)

3
Lưu ý: Chỉ sử dụng cho các mảng nguyên thủy. "RecursiveArrayIterator coi tất cả các đối tượng là có con và cố gắng đệ quy vào chúng." php.net/manual/en/class.recursivearrayiterator.php#106519
ReactiveRaven

4

Một giải pháp không đệ quy (nhưng hủy đơn hàng):

function flatten($ar) {
    $toflat = array($ar);
    $res = array();

    while (($r = array_shift($toflat)) !== NULL) {
        foreach ($r as $v) {
            if (is_array($v)) {
                $toflat[] = $v;
            } else {
                $res[] = $v;
            }
        }
    }

    return $res;
}

4

Trong PHP> = 5.3 và dựa trên câu trả lời của Luc M (câu đầu tiên), bạn có thể sử dụng các bao đóng như thế này

array_walk_recursive($aNonFlat, function(&$v, $k, &$t){$t->aFlat[] = $v;}, $objTmp);

Tôi thích điều này vì tôi không phải đặt mã của hàm trong dấu ngoặc kép như khi sử dụng create_ functions ()


1
nếu bạn đang sử dụng chức năng ẩn danh, bạn cũng có thể sử dụng một biến đóng cửa bắt trực tiếp chứ không phải là này objTempthứ
user102008

1
Có một lỗi trong PHP5.3.3 gây này sụp đổ - bugs.php.net/bug.php?id=52719
crazyphoton

2

Sử dụng các hàm bậc cao hơn (lưu ý: Tôi đang sử dụng các hàm ẩn danh nội tuyến , xuất hiện trong PHP 5.3):

function array_flatten($array) {
    return array_reduce(
        $array,
        function($prev, $element) {
            if (!is_array($element))
                $prev[] = $element;
            else
                $prev = array_merge($prev, array_flatten($element));
            return $prev;
        },
        array()
    );
}

1

Một cách tiếp cận mới dựa trên hàm ví dụ trước đó do hỗn loạn đệ trình, sửa lỗi ghi đè các khóa chuỗi trong đa mảng:

# Flatten a multidimensional array to one dimension, optionally preserving keys.
# $array - the array to flatten
# $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
# $out - internal use argument for recursion

function flatten_array($array, $preserve_keys = 2, &$out = array(), &$last_subarray_found) 
{
        foreach($array as $key => $child)
        {
            if(is_array($child))
            {
                $last_subarray_found = $key;
                $out = flatten_array($child, $preserve_keys, $out, $last_subarray_found);
            }
            elseif($preserve_keys + is_string($key) > 1)
            {
                if ($last_subarray_found)
                {
                    $sfinal_key_value = $last_subarray_found . "_" . $key;
                }
                else
                {
                    $sfinal_key_value = $key;
                }
                $out[$sfinal_key_value] = $child;
            }
            else
            {
                $out[] = $child;
            }
        }

        return $out;
}

Example:
$newarraytest = array();
$last_subarray_found = "";
$this->flatten_array($array, 2, $newarraytest, $last_subarray_found);

1
/*consider $mArray as multidimensional array and $sArray as single dimensional array
this code will ignore the parent array
*/

function flatten_array2($mArray) {
    $sArray = array();

    foreach ($mArray as $row) {
        if ( !(is_array($row)) ) {
            if($sArray[] = $row){
            }
        } else {
            $sArray = array_merge($sArray,flatten_array2($row));
        }
    }
    return $sArray;
}

1

bạn có thể thử điều này:

function flat_an_array($a)
{
    foreach($a as $i)
    {
        if(is_array($i)) 
        {
            if($na) $na = array_merge($na,flat_an_array($i));
            else $na = flat_an_array($i);
        }
        else $na[] = $i;
    }
    return $na;
}

1

Nếu bạn không sao với việc mất các khóa mảng, bạn có thể san phẳng một mảng nhiều chiều bằng cách sử dụng bao đóng đệ quy làm lệnh gọi lại sử dụng array_values ​​(), đảm bảo rằng lệnh gọi lại này là một tham số cho array_walk (), như sau.

<?php  

$array = [1,2,3,[5,6,7]];
$nu_array = null;
$callback = function ( $item ) use(&$callback, &$nu_array) {
    if (!is_array($item)) {
    $nu_array[] = $item;
    }
    else
    if ( is_array( $item ) ) {
     foreach( array_values($item) as $v) {
         if ( !(is_array($v))) {
             $nu_array[] = $v;
         }
         else
         { 
             $callback( $v );
         continue;
         }    
     }
    }
};

array_walk($array, $callback);
print_r($nu_array);

Một nhược điểm của ví dụ trước là nó liên quan đến việc viết nhiều mã hơn so với giải pháp sau sử dụng array_walk_recursive () cùng với một lệnh gọi lại được đơn giản hóa:

<?php  

$array = [1,2,3,[5,6,7]];

$nu_array = [];
array_walk_recursive($array, function ( $item ) use(&$nu_array )
                     {
                         $nu_array[] = $item;
                     }
);
print_r($nu_array);

Xem mã trực tiếp

Ví dụ này có vẻ thích hợp hơn ví dụ trước, ẩn các chi tiết về cách các giá trị được trích xuất từ ​​một mảng đa chiều. Chắc chắn, lặp đi lặp lại xảy ra, nhưng cho dù nó đòi hỏi đệ quy hoặc (các) cấu trúc điều khiển, bạn sẽ chỉ biết khi đọc qua array.c . Vì lập trình chức năng tập trung vào đầu vào và đầu ra hơn là những chi tiết vụn vặt của việc thu được kết quả, nên chắc chắn người ta có thể không quan tâm đến việc lặp lại hậu trường diễn ra như thế nào, đó là cho đến khi một nhà tuyển dụng đặt ra câu hỏi như vậy.


1

Tôi đã tìm thấy một cách đơn giản để chuyển đổi mảng đa cấp thành một. Tôi sử dụng hàm "http_build_query" để chuyển đổi mảng thành chuỗi url. Sau đó, tách chuỗi với boom và giải mã giá trị.

Đây là một mẫu.

$converted = http_build_query($data);
$rows = explode('&', $converted);
$output = array();
foreach($rows AS $k => $v){
   list($kk, $vv) = explode('=', $v);
   $output[ urldecode($kk) ] =  urldecode($vv);
}
return $output;

1

Xin lỗi vì không có lỗi nào, nhưng không có câu trả lời nào trong số các câu trả lời được cung cấp làm được điều mà tôi hiểu theo trực giác là "làm phẳng một mảng đa chiều". Cụ thể là trường hợp này:

[
  'a' => [
    'b' => 'value',
  ]
]

tất cả các giải pháp được cung cấp sẽ làm phẳng nó thành chỉ ['value'], nhưng điều đó làm mất thông tin về khóa và độ sâu, cộng với nếu bạn có một khóa 'b' khác ở nơi khác, nó sẽ ghi đè lên chúng.

Tôi muốn nhận được một kết quả như thế này:

[
  'a_b' => 'value',
]

array_walk_recursive không chuyển thông tin về khóa mà nó hiện đang đệ quy, vì vậy tôi đã làm điều đó chỉ với đệ quy đơn giản:

function flatten($array, $prefix = '') {
    $return = [];
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $return = array_merge($return, flatten($value, $prefix . $key . '_'));
        } else {
            $return[$prefix . $key] = $value;
        }
    }
    return $return;
}

Sửa đổi tiền tố $ và dấu phân cách '_' theo ý bạn.

Sân chơi tại đây: https://3v4l.org/0B8hf



0

Cách tiếp cận đơn giản..Xem nó qua đệ quy ..

<?php

function flatten_array($simple){
static $outputs=array();
foreach ( $simple as $value)
{
if(is_array($value)){
    flatten_array($value);
}
else{
    $outputs[]=$value;
}

}
return $outputs;
}

$eg=['s'=>['p','n'=>['t']]];
$out=flatten_array($eg);
print_r($out);

?>

Tại sao lại sử dụng staticmột ý tưởng có thể không tốt cho nhiệm vụ này? Lưu giữ dữ liệu ngoài ý muốn. Điều này chắc chắn sẽ khiến các lập trình viên ngạc nhiên nếu họ không biết / mong đợi hành vi này. Hãy nhìn vào cuộc biểu tình này .
mickmackusa

Bạn đã đăng câu trả lời "chỉ có mã" - những câu trả lời này có giá trị thấp trên StackOverflow vì chúng không thể giáo dục OP và các nhà nghiên cứu trong tương lai. Vui lòng dành một chút thời gian để cải thiện câu trả lời này bằng cách bao gồm cách câu trả lời của bạn hoạt động và lý do tại sao bạn cảm thấy đó là một ý tưởng tốt hơn so với các câu trả lời trước đó.
mickmackusa 16/07/18

0

Ai đó có thể thấy điều này hữu ích, tôi đã gặp sự cố làm phẳng mảng ở một số chiều, tôi sẽ gọi nó là chiều cuối cùng, ví dụ: nếu tôi có mảng như:

array (
  'germany' => 
  array (
    'cars' => 
    array (
      'bmw' => 
      array (
        0 => 'm4',
        1 => 'x3',
        2 => 'x8',
      ),
    ),
  ),
  'france' => 
  array (
    'cars' => 
    array (
      'peugeot' => 
      array (
        0 => '206',
        1 => '3008',
        2 => '5008',
      ),
    ),
  ),
)

Hoặc là:

array (
  'earth' => 
  array (
    'germany' => 
    array (
      'cars' => 
      array (
        'bmw' => 
        array (
          0 => 'm4',
          1 => 'x3',
          2 => 'x8',
        ),
      ),
    ),
  ),
  'mars' => 
  array (
    'france' => 
    array (
      'cars' => 
      array (
        'peugeot' => 
        array (
          0 => '206',
          1 => '3008',
          2 => '5008',
        ),
      ),
    ),
  ),
)

Đối với cả hai mảng này khi tôi gọi phương thức bên dưới, tôi nhận được kết quả:

array (
  0 => 
  array (
    0 => 'm4',
    1 => 'x3',
    2 => 'x8',
  ),
  1 => 
  array (
    0 => '206',
    1 => '3008',
    2 => '5008',
  ),
)

Vì vậy, tôi đang làm phẳng đến kích thước mảng cuối cùng sẽ giữ nguyên, phương thức bên dưới có thể được cấu trúc lại để thực sự dừng lại ở bất kỳ loại cấp nào:

function flattenAggregatedArray($aggregatedArray) {
    $final = $lvls = [];
    $counter = 1;
    $lvls[$counter] = $aggregatedArray;


    $elem = current($aggregatedArray);

    while ($elem){
        while(is_array($elem)){
            $counter++;
            $lvls[$counter] = $elem;
            $elem =  current($elem);
        }

        $final[] = $lvls[$counter];
        $elem = next($lvls[--$counter]);
        while ( $elem  == null){
            if (isset($lvls[$counter-1])){
                $elem = next($lvls[--$counter]);
            }
            else{
                return $final;
            }
        }
    }
}

-1

Nếu bạn chỉ quan tâm đến các giá trị cho một khóa cụ thể, bạn có thể thấy phương pháp này hữu ích:

function valuelist($array, $array_column) {
    $return = array();
    foreach($array AS $row){
        $return[]=$row[$array_column];
    };
    return $return;
};

Thí dụ:

Đã cho $ get_role_action =

array(3) {
  [0]=>
  array(2) {
    ["ACTION_CD"]=>
    string(12) "ADD_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [1]=>
  array(2) {
    ["ACTION_CD"]=>
    string(13) "LINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [2]=>
  array(2) {
    ["ACTION_CD"]=>
    string(15) "UNLINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
}

hơn $variables['role_action_list']=valuelist($get_role_action, 'ACTION_CD');sẽ dẫn đến:

$variables["role_action_list"]=>
  array(3) {
    [0]=>
    string(12) "ADD_DOCUMENT"
    [1]=>
    string(13) "LINK_DOCUMENT"
    [2]=>
    string(15) "UNLINK_DOCUMENT"
  }

Từ đó, bạn có thể thực hiện tra cứu giá trị như sau:

if( in_array('ADD_DOCUMENT', $variables['role_action_list']) ){
    //do something
};

Đây là một phiên bản PHP của một hàm CFML có cùng tên.
Jeromy French

Tôi đã phản đối vì đó là câu trả lời đúng cho câu hỏi sai.
mickmackusa,

-1

bất kỳ điều nào trong số này không làm việc cho tôi ... vì vậy phải tự chạy nó. hoạt động tốt:

function arrayFlat($arr){
$out = '';
    foreach($arr as $key => $value){

        if(!is_array($value)){
            $out .= $value.',';
        }else{
            $out .= $key.',';
            $out .= arrayFlat($value);
        }

    }
    return trim($out,',');
}


$result = explode(',',arrayFlat($yourArray));
echo '<pre>';
print_r($result);
echo '</pre>';

Câu trả lời chỉ có mã này không hoạt động như mong muốn. 3v4l.org/U3bfp <- bằng chứng Đây là lý do tôi phản đối.
mickmackusa

-1

Cho mảng đa chiều và chuyển đổi nó thành một chiều, có thể được thực hiện bằng cách bỏ đặt tất cả các giá trị có mảng và lưu chúng vào chiều thứ nhất, ví dụ:

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

Tôi đã phản đối câu trả lời này vì nó không hoạt động trên bất kỳ phiên bản nào. 3v4l.org/7cO9N (Bằng chứng) Ngoài ra, each()không được chấp nhận từ php7.2.
mickmackusa,
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.