skip to Main Content

I have a list of items in a PHP array, and I’m trying to write a function to get the values for the relative 3 lowest levels from each array block. I could format the array hierarchically based on the parent_id field, but now I’d like to filter it down to the relative 3 lowest levels only.

Here is the array that I’m working with (the values are just examples):

array (
  0 => 
  array (
    'id' => 1,
    'parent_id' => NULL,
    'name' => 'Home',
    'children' => 
    array (
      0 => 
      array (
        'id' => 3,
        'parent_id' => 1,
        'name' => 'Contact',
        'children' => 
        array (
          0 => 
          array (
            'id' => 6,
            'parent_id' => 3,
            'name' => 'Phone',
          ),
          1 => 
          array (
            'id' => 7,
            'parent_id' => 3,
            'name' => 'Email',
          ),
        ),
      ),
    ),
  ),
  1 => 
  array (
    'id' => 2,
    'parent_id' => NULL,
    'name' => 'About',
    'children' => 
    array (
      0 => 
      array (
        'id' => 4,
        'parent_id' => 2,
        'name' => 'History',
      ),
      1 => 
      array (
        'id' => 5,
        'parent_id' => 2,
        'name' => 'Team',
        'children' => 
        array (
          0 => 
          array (
            'id' => 8,
            'parent_id' => 5,
            'name' => 'John',
            'children' => 
            array (
              0 => 
              array (
                'id' => 12,
                'parent_id' => 8,
                'name' => 'John 2',
              ),
            ),
          ),
          1 => 
          array (
            'id' => 10,
            'parent_id' => 5,
            'name' => 'Alex',
          ),
        ),
      ),
    ),
  ),
  2 => 
  array (
    'id' => 9,
    'parent_id' => 22,
    'name' => 'Mary',
  ),
)

The PHP function I’m trying to write should result in the following output:

  • About

    • History

    • Team

      • John
  • Home

    • Contact

      • Phone

      • Email

  • Mary

With real data, there might be more or fewer levels, so the function should be able to find the lowest levels, no matter if there are only 4 (as in this example), or 12.

I was able to write a function that returns the top 3 levels from the array, but I’m looking for a good way to return the bottom 3 levels of each array block.

Thanks for the help in advance!

Additional context

The original array from PHP:

$flat_array = array(
    array('id' => 1, 'parent_id' => null, 'name' => 'Home'),
    array('id' => 2, 'parent_id' => 1, 'name' => 'About'),
    array('id' => 3, 'parent_id' => 1, 'name' => 'Contact'),
    array('id' => 4, 'parent_id' => 2, 'name' => 'History'),
    array('id' => 5, 'parent_id' => 2, 'name' => 'Team'),
    array('id' => 6, 'parent_id' => 3, 'name' => 'Phone'),
    array('id' => 7, 'parent_id' => 3, 'name' => 'Email'),
    array('id' => 8, 'parent_id' => 5, 'name' => 'John'),
    array('id' => 9, 'parent_id' => 11, 'name' => 'Mary'),
);

The function I’m transforming this with into a hierarchical array:

function hierarchyOrder($flat_array) {
    $resultIds = get_ids(($flat_array));
    $map = array();
    foreach ($flat_array as $arr) {
        $map[$arr['id']] = $arr;
    }
    $hierarchy = array();
    foreach ($flat_array as $arr) {
        if (($arr['parent_id'] !== null) AND (in_array($arr["parent_id"], $resultIds))) {
            $map[$arr['parent_id']]['children'][] = &$map[$arr['id']];
        }
        else {
            $hierarchy[] = &$map[$arr['id']];
        }
    }
    return $hierarchy;
}

function get_ids($flat_array) {
    return array_map(function($item) {
      return $item['id'];
    }, $flat_array);
}

Previously, I tried to build up the function by modifying a similar function that returns the top 3 levels of an array. My solution was not dynamic enough, and I was not able to figure out a logic that reliably can return the bottom 3 levels. My starting point was:

function returnCorrectLevels($input) {
  $result = [];

  foreach ($input as $item) {
      $level1 = [
          'id' => $item['id'],
          'parent_id' => $item['parent_id'],
          'name' => $item['name'],
      ];

      if (isset($item['children'])) {
          $level2 = [];
          foreach ($item['children'] as $child1) {
              $level2[] = [
                  'id' => $child1['id'],
                  'parent_id' => $child1['parent_id'],
                  'name' => $child1['name'],
              ];

              if (isset($child1['children'])) {
                  $level3 = [];
                  foreach ($child1['children'] as $child2) {
                      $level3[] = [
                          'id' => $child2['id'],
                          'parent_id' => $child2['parent_id'],
                          'name' => $child2['name'],
                      ];
                  }
                  $level2[count($level2)-1]['children'] = $level3;
              }
          }
          $level1['children'] = $level2;
      }
      $result[] = $level1;
  }
  return $result;
}

2

Answers


  1. Initially, as per the desired output mentioned in the question, the parent_id of About menu item has to be null.

    <?php 
    // Base array to arrange
    $flat_array = array(
        array('id' => 1, 'parent_id' => null, 'name' => 'Home'),
        array('id' => 2, 'parent_id' => null, 'name' => 'About'),
        array('id' => 3, 'parent_id' => 1, 'name' => 'Contact'),
        array('id' => 4, 'parent_id' => 2, 'name' => 'History'),
        array('id' => 5, 'parent_id' => 2, 'name' => 'Team'),
        array('id' => 6, 'parent_id' => 3, 'name' => 'Phone'),
        array('id' => 7, 'parent_id' => 3, 'name' => 'Email'),
        array('id' => 8, 'parent_id' => 5, 'name' => 'John'),
        array('id' => 9, 'parent_id' => 11, 'name' => 'Mary'),
    );
    
    // Obtaining hierarchy order used from existing question
    function hierarchyOrder($flat_array) {
    
        // Getting all parent IDs from the array
        $resultIds = get_ids(($flat_array));
       
        // empty output array 
        $map = array();
    
        // iterating through to get array elements
        foreach ($flat_array as $arr) {
            $map[$arr['id']] = $arr;
        }
        
        // Blank output array
        $hierarchy = array();
    
        // Iterating through $flat_array to get child elements
        foreach ($flat_array as $arr) {
            if (($arr['parent_id'] !== null) AND (in_array($arr["parent_id"], $resultIds))) {
                $map[$arr['parent_id']]['children'][] = &$map[$arr['id']];
            }
            else {
                $hierarchy[] = &$map[$arr['id']];
            }
        }
        
        return $hierarchy;
    }
    
    // function to get parent IDs 
    function get_ids($flat_array) {
        return array_map(function($item) {
          return $item['id'];
        }, $flat_array);
    }
    
    //  assigning the final result to a variable
    $result = hierarchyOrder($flat_array);
    ?>
    <ul>
        <?php foreach($result as $item){
            echo "<li><strong>{$item['name']}</strong>";
            if(isset($item['children']) AND count($item['children']) > 0)
            {
                echo "<ul>";
                    foreach($item['children'] as $child)
                    {
                        echo "<li>{$child['name']}";
                        if(isset($child['children']) AND count($child['children']) > 0)
                        {
                            echo "<ul>";
                            foreach($child['children'] as $subchild)
                            {
                                echo "<li>{$subchild['name']}</li>";
                            }
                            echo "</ul>";
                        }
                        echo "</li>";
                    }
                echo "</ul>";
            }
            echo "</li>";
        }?>
    </ul>
    

    Final output will be as follows:
    Screenshot of final output as desired

    Edited after reading the comments provided by the author

    <?php 
    // Base array to arrange
    $flat_array = array(
        array('id' => 1, 'parent_id' => null, 'name' => 'Home'),
        array('id' => 2, 'parent_id' => null, 'name' => 'About'),
        array('id' => 3, 'parent_id' => 1, 'name' => 'Contact'),
        array('id' => 4, 'parent_id' => 2, 'name' => 'History'),
        array('id' => 5, 'parent_id' => 2, 'name' => 'Team'),
        array('id' => 6, 'parent_id' => 3, 'name' => 'Phone'),
        array('id' => 7, 'parent_id' => 3, 'name' => 'Email'),
        array('id' => 8, 'parent_id' => 5, 'name' => 'John'),
        array('id' => 9, 'parent_id' => 11, 'name' => 'Mary'),
        array('id' => 10, 'parent_id' => 8, 'name' => 'Kiran'),
    );
    
    // Obtaining hierarchy order used from existing question
    function hierarchyOrder($flat_array) {
    
        // Getting all parent IDs from the array
        $resultIds = get_ids(($flat_array));
       
        // empty output array 
        $map = array();
    
        // iterating through to get array elements
        foreach ($flat_array as $arr) {
            $map[$arr['id']] = $arr;
        }
        
        // Blank output array
        $hierarchy = array();
    
        // Iterating through $flat_array to get child elements
        foreach ($flat_array as $arr) {
            if (($arr['parent_id'] !== null) AND (in_array($arr["parent_id"], $resultIds))) {
                $map[$arr['parent_id']]['children'][] = &$map[$arr['id']];
            }
            else {
                $hierarchy[] = &$map[$arr['id']];
            }
        }
        
        return $hierarchy;
    }
    
    // function to get parent IDs 
    function get_ids($flat_array) {
        return array_map(function($item) {
          return $item['id'];
        }, $flat_array);
    }
    
    //  assigning the final result to a variable
    $result = hierarchyOrder($flat_array);
    
    
    // function to generate menu items - recursively
    function prepare_menu_items($menuArray)
    {
        $output = '';
        foreach($menuArray as $item){
            $output .= "<li>{$item['name']}";
            if(isset($item['children']) AND count($item['children']) > 0)
            {
                $output .= "<ul>";
                $output .= prepare_menu_items($item['children']);
                $output .= "</ul>";
            }
            $output .= "</li>";
        }
        
        return $output;
    }
    
    ?>
    <ul>
        <?=prepare_menu_items($result)?>
    </ul>
    

    The above code is accommodating n number of levels, picking the bottom 3 levels is bit challenging with current example given.

    You can try to positively arranged if the array is sored decending from bottom to top. You can try as per my comment below.

    Login or Signup to reply.
  2. ok i fix it

    $flat_array = array(
    array('id' => 1, 'parent_id' => null, 'name' => 'Nikos Kontominas'),
    array('id' => 2, 'parent_id' => null, 'name' => 'Ioanna Kontominas'),
    array('id' => 3, 'parent_id' => 1, 'name' => 'Panagiotis Kontominas'),
    array('id' => 4, 'parent_id' => 2, 'name' => 'George Filipakos'),
    array('id' => 5, 'parent_id' => 2, 'name' => 'Katina Filipakos'),
    array('id' => 6, 'parent_id' => 3, 'name' => 'Nikos Kontominas'),
    array('id' => 7, 'parent_id' => 3, 'name' => 'Elpida Kontominas'),
    array('id' => 8, 'parent_id' => 5, 'name' => 'John Travolta'),
    array('id' => 9, 'parent_id' => null, 'name' => 'Mary Kontominas'),
    array('id' => 10, 'parent_id' => 7, 'name' => 'Katia Gianakakos'),
    array('id' => 11, 'parent_id' => 10, 'name' => 'Elpida Hover'),
    );
    
    
     ///////////////////////////
    echo '<ul>';
    returbData($flat_array);
    echo '</ul>';
    function returbData($arr){
    $record=count($arr);    
     foreach ($arr as $item) {
        if($item['parent_id']==null){
            echo '<li>'.$item['name'];
            repeat($item['id'],$arr);
            }
        }
      }
    
    
    
      function repeat($item,$arr){
      echo'<ul>';
       foreach ($arr as $parent) {
        if($item==($parent['parent_id'])){
            
            echo '<li>'.$parent['name'];
            
            repeat($parent['id'],$arr);
          }
       }
       echo '</ul>';
       echo '</li>';    
    
    
    }
    

    and you have output page code

    <ul>
    <li>Nikos Kontominas
        <ul><li>Panagiotis Kontominas
            <ul><li>Nikos Kontominas
                <ul></ul>
                </li>
                <li>Elpida Kontominas
                    <ul><li>Katia Gianakakos
                        <ul><li>Elpida Hover
                            <ul></ul>
                            </li>
                        </ul>
                        </li>
                    </ul>
                </li>
            </ul>
            </li>
        </ul>
    </li>
    <li>Ioanna Kontominas
        <ul><li>George Filipakos
                <ul></ul>
            </li>
            <li>Katina Filipakos
                <ul><li>John Travolta
                    <ul></ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>Mary Kontominas
        <ul></ul>
    </li>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search