Convert PHP array to JSON tree

前端 未结 3 1619
一整个雨季
一整个雨季 2020-12-04 00:48

I have got a array in this format:

array(
    array(\'id\' => 1, \'parent_id\' => null, \'name\' => \'lorem ipsum\'),
    array(\'id\' => 2, \'pa         


        
相关标签:
3条回答
  • 2020-12-04 01:15

    My solution:

    $data = array(
        array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'),
        array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'),
        array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'),
        array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'),
        array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'),
        array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'),
    );
    
    $itemsByReference = array();
    
    // Build array of item references:
    foreach($data as $key => &$item) {
       $itemsByReference[$item['id']] = &$item;
       // Children array:
       $itemsByReference[$item['id']]['children'] = array();
       // Empty data class (so that json_encode adds "data: {}" ) 
       $itemsByReference[$item['id']]['data'] = new StdClass();
    }
    
    // Set items as children of the relevant parent item.
    foreach($data as $key => &$item)
       if($item['parent_id'] && isset($itemsByReference[$item['parent_id']]))
          $itemsByReference [$item['parent_id']]['children'][] = &$item;
    
    // Remove items that were added to parents elsewhere:
    foreach($data as $key => &$item) {
       if($item['parent_id'] && isset($itemsByReference[$item['parent_id']]))
          unset($data[$key]);
    }
    
    // Encode:
    $json = json_encode($data);
    
    0 讨论(0)
  • 2020-12-04 01:17

    My take (I know an answer has been accepted, but I worked on this so I'm gonna post id =P)

    // Test data
    $data = array(
        array('id' => 1, 'parent_id' => null, 'name' => 'lorem ipsum'),
        array('id' => 2, 'parent_id' => 1, 'name' => 'lorem ipsum1'),
        array('id' => 3, 'parent_id' => 1, 'name' => 'lorem ipsum2'),
        array('id' => 4, 'parent_id' => 2, 'name' => 'lorem ipsum3'),
        array('id' => 5, 'parent_id' => 3, 'name' => 'lorem ipsum4'),
        array('id' => 6, 'parent_id' => null, 'name' => 'lorem ipsum5'),
    );
    
    // Randomize, because the data may not be in a top-down order
    shuffle( $data );
    
    // Parse and inspect the result
    $builder = new TreeBuilder( $data );
    echo '<pre>', print_r( $builder->getTree() ), '</pre>';
    
    
    class TreeBuilder
    {
      protected $leafIndex = array();
      protected $tree      = array();
      protected $stack;
    
      function __construct( $data )
      {
        $this->stack = $data;
    
        while( count( $this->stack ) )
        {
          $this->branchify( array_shift( $this->stack ) );
        }
      }
    
      protected function branchify( &$leaf )
      {
        // Root-level leaf?
        if ( null === $leaf['parent_id'] )
        {
          $this->addLeaf( $this->tree, $leaf );
        }
        // Have we found this leaf's parent yet?
        else if ( isset( $this->leafIndex[$leaf['parent_id']] ) )
        {
          $this->addLeaf( $this->leafIndex[$leaf['parent_id']]['children'], $leaf );
        } else {
          // Nope, put it back on the stack
          $this->stack[] = $leaf;
        }
      }
    
      protected function addLeaf( &$branch, $leaf )
      {
        // Add the leaf to the branch
        $branch[] = array(
            'id'       => $leaf['id']
          , 'name'     => $leaf['name']
          , 'data'     => new stdClass
          , 'children' => array()
        );
    
        // Store a reference so we can do an O(1) lookup later
        $this->leafIndex[$leaf['id']] = &$branch[count($branch)-1];
      }
    
      protected function addChild( $branch, $leaf )
      {
        $this->leafIndex[$leaf['id']] &= $branch['children'][] = $leaf;
      }
    
      public function getTree()
      {
        return $this->tree;
      }
    }
    
    0 讨论(0)
  • 2020-12-04 01:36

    Here's code to do what you need. It does not need the items to be in parent-children order in the array, but will finish faster if they are.

    Please study the comments to understand what the code is doing and why; and if you still have questions, ask them too!

    // Assume your array is $data
    
    $root = new stdClass; // this is your root item
    $objectMap = array(); // this holds objects indexed by their id
    
    // Since we need to iterate over the array, but there may be no guarantee
    // that an item's parent will be always encountered before the item itself,
    // we loop as many times as needed, skipping items whose parent we have not
    // yet seen. Hopefully we will see it later and be able to process these
    // items in the next iteration.
    while (!empty($data)) {
    
        // Remember how many items there are when starting the loop
        $count = count($data);
    
        // Do the actual work!
        foreach ($data as $key => $row) {
            $parentId = $row['parent_id'];
    
            if ($parentId === null) {
                // We just met the root element
                $current = $root;
            }
            else if (isset($objectMap[$parentId])) {
                // We met an element with a parent that we have already seen
                $current = new stdClass;
            }
            else {
                // We met an element with an unknown parent; ignore it for now
                continue;
            }
    
            // Put the current element on the map so that its children will
            // be able to find it when we meet them
            $objectMap[$row['id']] = $current;
    
            // Add the item to its parent's children array
            $objectMap[$parentId]->children[] = $current;
    
            // Set the item's properties
            $current->id = $row['id'];
            $current->name = $row['name'];
            $current->data = new stdClass; // always empty
            $current->children = array();
    
            // We successfully processed this, remove it (see why below!)
            unset($data[$key]);
        }
    
        // OK, we looped over the array once. If the number of items has
        // not been reduced at all, it means that the array contains only
        // items whose parents do not exist. Instead of looping forever,
        // let's just take what we are given and stop here.
        if ($count == count($data)) {
            break;
        }
    
        // If there are still items in $data, we will now iterate again
        // in the hope of being able to process them in the next iteration
    }
    
    // All set! If $data is not empty now, it means there were items
    // with invalid parent_ids to begin with.
    $output = json_encode($root);
    
    0 讨论(0)
提交回复
热议问题