Плоский массив PHP в дерево иерархии

у меня есть массив со следующими ключами

id   
parent_id
name

пример массива:

array(7) {
  [0]=>
  array(3) {
    ["id"]=>
    string(1) "4"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 4"
  }
  [1]=>
  array(3) {
    ["id"]=>
    string(1) "5"
    ["parent_id"]=>
    string(1) "1"
    ["name"]=>
    string(19) "Second Level Page 1"
  }
  [2]=>
  array(3) {
    ["id"]=>
    string(1) "6"
    ["parent_id"]=>
    string(1) "2"
    ["name"]=>
    string(19) "Second Level Page 2"
  }
  [3]=>
  array(3) {
    ["id"]=>
    string(1) "7"
    ["parent_id"]=>
    string(1) "5"
    ["name"]=>
    string(18) "Third Level Page 1"
  }
  [4]=>
  array(3) {
    ["id"]=>
    string(1) "3"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 3"
  }
  [5]=>
  array(3) {
    ["id"]=>
    string(1) "2"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 2"
  }
  [6]=>
  array(3) {
    ["id"]=>
    string(1) "1"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 1"
  }
}

что я хотел бы сделать, это отобразить дерево иерархии с помощью этого массива, код, который у меня есть на данный момент, производит:

Top Level Page 4
--Second Level Page 1
---Second Level Page 2
----Third Level Page 1
Top Level Page 3
Top Level Page 2
Top Level Page 1

в идеале мне нужно произвести ниже результат, но с неограниченным уровнем:

Top Level Page 4
-Second Level Page 1
-Second Level Page 2
--Third Level Page 1
Top Level Page 3
Top Level Page 2
Top Level Page 1

код у меня есть до сих пор:

$level = 1;
        foreach ($data as $row) {
            if ($row['parent_id'] == 0) {
                echo $row['name'] . '<br/>';
            } else {
                $level++;
                foreach ($data as $m) {
                    if ($m['parent_id'] === $row['parent_id']) {
                        $c = 0;
                        $append = '';
                        while ($c < $level) {
                            $append.="-";
                            $c++;
                        }
                        echo $append . $row['name'] . '<br/>';
                    }
                }
            }
        }
    }

если бы кто-нибудь мог дать мне несколько советов о том, как этого достичь, это было бы много оцененный.

я нашел решение здесь:создать вложенный список из массива PHP для раскрывающегося списка выберите поле

3 ответов


вы должны использовать рекурсию.

вот пример кода:

$datas = array(
    array('id' => 1, 'parent' => 0, 'name' => 'Page 1'),
    array('id' => 2, 'parent' => 1, 'name' => 'Page 1.1'),
    array('id' => 3, 'parent' => 2, 'name' => 'Page 1.1.1'),
    array('id' => 4, 'parent' => 3, 'name' => 'Page 1.1.1.1'),
    array('id' => 5, 'parent' => 3, 'name' => 'Page 1.1.1.2'),
    array('id' => 6, 'parent' => 1, 'name' => 'Page 1.2'),
    array('id' => 7, 'parent' => 6, 'name' => 'Page 1.2.1'),
    array('id' => 8, 'parent' => 0, 'name' => 'Page 2'),
    array('id' => 9, 'parent' => 0, 'name' => 'Page 3'),
    array('id' => 10, 'parent' => 9, 'name' => 'Page 3.1'),
    array('id' => 11, 'parent' => 9, 'name' => 'Page 3.2'),
    array('id' => 12, 'parent' => 11, 'name' => 'Page 3.2.1'),
    );

function generatePageTree($datas, $parent = 0, $depth=0){
    $ni=count($datas);
    if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion
    $tree = '<ul>';
    for($i=0; $i < $ni; $i++){
        if($datas[$i]['parent'] == $parent){
            $tree .= '<li>';
            $tree .= $datas[$i]['name'];
            $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1);
            $tree .= '</li>';
        }
    }
    $tree .= '</ul>';
    return $tree;
}

echo(generatePageTree($datas));

вы можете проверить его по адресу:http://phpfiddle.org/main/code/1qy-5fj

или если вы хотите точную формат:

function generatePageTree($datas, $parent = 0, $depth = 0){
    $ni=count($datas);
    if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion
    $tree = '';
    for($i=0; $i < $ni; $i++){
        if($datas[$i]['parent'] == $parent){
            $tree .= str_repeat('-', $depth);
            $tree .= $datas[$i]['name'] . '<br/>';
            $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1);
        }
    }
    return $tree;
}

тест:http://phpfiddle.org/main/code/jw3-s1j


можно использовать класс FlatToTreeConverter из вспомогательной библиотеки Gears:

<?php
namespace Cosmologist\Gears\Collection;
/**
 * Class able to convert a flat array with parent ID's to a nested tree
 */
class FlatToTreeConverter
{
    /**
     * Convert a flat array with parent ID's to a nested tree
     *
     * @link http://blog.tekerson.com/2009/03/03/converting-a-flat-array-with-parent-ids-to-a-nested-tree/
     *
     * @param array  $array           Flat array
     * @param string $idKeyName       Key name for the element containing the item ID
     * @param string $parentIdKey     Key name for the element containing the parent item ID
     * @param string $childNodesField Key name for the element for placement children
     *
     * @return array
     */
    public static function convert(array $array, $idKeyName = 'id', $parentIdKey = 'parentId', $childNodesField = 'children')
    {
        $indexed = array();
        // first pass - get the array indexed by the primary id
        foreach ($array as $row) {
            $indexed[$row[$idKeyName]]                   = $row;
            $indexed[$row[$idKeyName]][$childNodesField] = array();
        }
        // second pass
        $root = array();
        foreach ($indexed as $id => $row) {
            $indexed[$row[$parentIdKey]][$childNodesField][$id] = &$indexed[$id];
            if (!$row[$parentIdKey]) {
                $root[$id] = &$indexed[$id];
            }
        }
        return $root;
    }
}

не уверен, что вы уже нашли ответ, но я искал то же самое решение сегодня и, наконец, сделал свое собственное решение. Приведенный ниже код-это класс, который я только что создал, и он работает с массивами и объектами PHP и рекурсивен для неограниченного количества измерений.

GitHub https://github.com/DukeOfMarshall/PHP-Array-Heirarchy-Display

простой пример использования этого кода:

<?php

require_once('Arrays.class.php');
$display = new Array_Functions();

$display->display_hierarchy($multidimensional_array);

?>

есть и другие варианты это также можно установить,но это было просто прямое отображение массива или объекта.

<?php

class Array_Functions {
public $number_of_tabs  = 3; # The default number of tabs to use when branching out
private $counter            = 0; # The counter to use for the number of tab iterations to use on the current branch

public $display_square_brackets     = TRUE; 
public $display_squiggly_brackets = FALSE;
public $display_parenthesis           = FALSE;

public $display_apostrophe  = TRUE;
public $display_quotes        = FALSE;

public function __construct(){
}

/**
 * Displays the array in an organized heirarchy and even does so recursively
 * 
 * $array ARRAY - The array to display in a heirarchy
 * 
 * $key_bookends STRING - The character to place on either side of the array key when printed
 * @@ square - Displays a set of square brackets around the key (DEFAULT)
 * @@ squiggly - Displays a set of squiggly brackets around the key
 * @@ parenthesis - Displays a set of parenthesis around the key
 * @@ FALSE - Turns off the display of bookends around the array key
 * 
 * $key_padding STRING - The padding to use around the array key with printed
 * @@ quotes - Pads the array key with double quotes when printed
 * @@ apostrophe - Pads the array key with apostrophes when printed (DEFAULT)
 * @@ FALSE - Turns off the display of padding around the array key
 * 
 * $number_of_tabs_to_use INT - The number of tabs to use when a sub array within the array creates a branch in the heirarchy
 * 
 */
public function display_hierarchy($array, $key_bookends = '', $key_padding = '', $number_of_tabs_to_use = ''){
    # Convert the input to a JSON and then back to an array just to make sure we know what we're working with
    $array = $this->convert_object_to_array($array);

    # If the $array variable is still not an array, then error out.
    # We're not going to fool around with your stupidity
    if(gettype($array) != 'array'){
        echo 'Value submitted was '.strtoupper(gettype($array)).' instead of ARRAY or OBJECT. Only arrays or OBJECTS are allowed Terminating execution.';
        exit();
    }

    # Establish the bookend variables
    if($key_bookends != '' || !$key_bookends){
        if(strtolower($key_bookends) == 'square'){
            $this->display_square_brackets      = TRUE;
            $this->display_squiggly_brackets    = FALSE;
            $this->display_parenthesis            = FALSE;
        }elseif(strtolower($key_bookends) == 'squiggly'){
            $this->display_square_brackets      = TRUE;
            $this->display_squiggly_brackets    = TRUE;
            $this->display_parenthesis            = FALSE;
        }elseif(strtolower($key_bookends) == 'parenthesis'){
            $this->display_square_brackets      = FALSE;
            $this->display_squiggly_brackets    = FALSE;
            $this->display_parenthesis          = TRUE;
        }elseif(!$key_bookends){
            $this->display_square_brackets      = FALSE;
            $this->display_squiggly_brackets    = FALSE;
            $this->display_parenthesis            = FALSE;
        }
    }


    # Establish the padding variables
    if($key_padding != '' || !$key_padding){
        if(strtolower($key_padding) == 'apostrophe'){
            $this->display_apostrophe = TRUE;
            $this->display_quotes       = FALSE;
        }elseif(strtolower($key_padding) == 'quotes'){
            $this->display_apostrophe = FALSE;
            $this->display_quotes       = TRUE;
        }elseif(!$key_padding){
            $this->display_apostrophe = FALSE;
            $this->display_quotes       = FALSE;
        }
    }       

    # Establish variable for the number of tabs
    if(isset($number_of_tabs_to_use) && $number_of_tabs_to_use != ''){
        $this->number_of_tabs = $number_of_tabs_to_use;
    }

    foreach($array as $key => $value){
        $this->insert_tabs();

        if(is_array($value)){
            echo $this->display_padding($key)." => {<BR>";

            $this->counter++;
            $this->display_hierarchy($value);
            $this->counter--;
            $this->insert_tabs();
            echo '} <BR>';
        }else{
            echo $this->display_padding($key)." => ".$value.'<BR>';
        }
    }
}

# Inserts tab spaces for sub arrays when a sub array triggers a branch in the heirarchy
# Helps to make the display more human readable and easier to understand
private function insert_tabs(){
    for($i=1; $i<=$this->counter; $i++){
        for($x=1; $x<=$this->number_of_tabs; $x++){
            echo '&emsp;';
        }
    }
}

# Takes a PHP object and converts it to an array
# Works with single dimension and multidimensional arrays
public function convert_object_to_array($object){
    $object = json_decode(json_encode($object), TRUE);
    return $object;
}

# Sets the displayed padding around the array keys when printed on the screen
public function display_padding($value){
    $default_container = "['VALUE_TO_REPLACE']";

    $value = str_replace("VALUE_TO_REPLACE", $value, $default_container);

    if($this->display_square_brackets){
    }elseif($this->display_squiggly_brackets){
        $value = str_replace('[', '{', $value);
        $value = str_replace(']', '}', $value);
    }elseif($this->display_parenthesis){
        $value = str_replace('[', '(', $value);
        $value = str_replace(']', ')', $value);
    }else{
        $value = str_replace('[', '', $value);
        $value = str_replace(']', '', $value);
    }

    if($this->display_apostrophe){
    }elseif($this->display_quotes){
        $value = str_replace("'", '"', $value);
    }else{
        $value = str_replace("'", '', $value);
    }

    return $value;
}
}

?>