skip to Main Content

The problem is that each child element is bound to each parent element, which is why everything is duplicated

<?php
$json = '[
    {"id":3633,"name":"Mobile phones and accessories","left":1,"right":18,"level":1,"elements":0},
    {"id":3638,"name":"Mobile phones","left":2,"right":3,"level":2,"elements":174},
    
    {"id":21396,"name":"Tablets","left":19,"right":24,"level":1,"elements":0},
    {"id":21450,"name":"Some Tablets","left":20,"right":21,"level":2,"elements":8}
    ]';

$data = json_decode($json, true);

function buildTree($data, $level = 1) {
    $tree = array();

    foreach ($data as $item) {
        if ($item['level'] == $level) {
            $node = array(
                'item' => $item,
                'children' => buildTree($data, $level + 1),
            );

            $tree[] = $node;
        }
    }

    return $tree;
}

$tree = buildTree($data);

print_r($tree);

?>

It turns out that this is the output of the elements

Array
(
    [0] => Array
        (
            [item] => Array
                (
                    [id] => 3633
                    [name] => Mobile phones and accessories
                    [left] => 1
                    [right] => 18
                    [level] => 1
                    [elements] => 0
                )

            [children] => Array
                (
                    [0] => Array
                        (
                            [item] => Array
                                (
                                    [id] => 3638
                                    [name] => Mobile phones
                                    [left] => 2
                                    [right] => 3
                                    [level] => 2
                                    [elements] => 174
                                )

                            [children] => Array
                                (
                                )

                        )

                    [1] => Array
                        (
                            [item] => Array
                                (
                                    [id] => 21450
                                    [name] => Some Tablets
                                    [left] => 20
                                    [right] => 21
                                    [level] => 2
                                    [elements] => 8
                                )

                            [children] => Array
                                (
                                )

                        )

                )

        )

    [1] => Array
        (
            [item] => Array
                (
                    [id] => 21396
                    [name] => Tablets
                    [left] => 19
                    [right] => 24
                    [level] => 1
                    [elements] => 0
                )

            [children] => Array
                (
                    [0] => Array
                        (
                            [item] => Array
                                (
                                    [id] => 3638
                                    [name] => Mobile phones
                                    [left] => 2
                                    [right] => 3
                                    [level] => 2
                                    [elements] => 174
                                )

                            [children] => Array
                                (
                                )

                        )

                    [1] => Array
                        (
                            [item] => Array
                                (
                                    [id] => 21450
                                    [name] => Some Tablets
                                    [left] => 20
                                    [right] => 21
                                    [level] => 2
                                    [elements] => 8
                                )

                            [children] => Array
                                (
                                )

                        )

                )

        )

)

Now I have every element with level = 2 tied to every element with level = 1
But there should be no duplication

What can be changed so that all elements are unique and belong to only one parent

2

Answers


  1. If you want it by parsed by order, all level 1 are siblings, and otherwise each item is a child of the previous then here’s a javascript pseudo-code.

    var arr = [
        {"id":3633,"name":"Mobile phones and accessories","left":1,"right":18,"level":1,"elements":0},
        {"id":3638,"name":"Mobile phones","left":2,"right":3,"level":2,"elements":174},
        {"id":3639,"name":"Mobile phones 2","left":2,"right":3,"level":3,"elements":174},
        
        {"id":21396,"name":"Tablets","left":19,"right":24,"level":1,"elements":0},
        {"id":21450,"name":"Some Tablets","left":20,"right":21,"level":2,"elements":8}
    ];
    
    var result = [];
    
    var previous = null;
    arr.forEach(function(item) {
      if (item.level == 1) {
        result.push({item})
        previous = item;
      } else {
        previous.children = previous.children || []
        previous.children.push({item})
        previous = item;
      }
    })
    
    console.log(result)
    Login or Signup to reply.
  2. I see two problems in your code:

    • it doesn’t handle the case when $level is greater than $item['level']
    • the recursive call uses the same array as first parameter, but doing that doesn’t preserve the "pointer" position, and the entire array is scanned at each call from the beginning.

    For the first point, a simple if suffices to solve the problem.
    For the second point I suggest to use an iterator in place of an array to keep the pointer positions trough the different calls.

    $data = new ArrayIterator(json_decode($json, true));
    
    function buildTree(iterator $data, int $level = 1): array {
        
        $tree = [];
      
        while ($data->valid()) {
            $item = $data->current();
            
            if ($item['level'] < $level)
                return $tree;
      
            if ($item['level'] === $level) {
                $data->next();
                
                $tree[] = [
                    'item' => $item,
                    'children' => buildTree($data, $level + 1)
                ];
            }
        }
    
        return $tree;
    }
    

    demo

    This code is written for PHP 8.x, feel free to remove the types in the function signature to make it work with older versions.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search