Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-structure n-level array with parent/child relation (PHP)

I want to restructure an array and some of the solutions on stuckoverflow helped me to make it "proper" for the 1-st level items, but you'll notice the array is n-level deep.

The method restructure() is not used recursively (it should be). It's probably wrong alltogether, and have no idea how to make it right.

The children key says there are children with the respective id's, parent key links the item to the parent id.

class FilterMenu {

    protected $tree = array();

    static protected $structure = array();

    public function __construct(array $tree)
    {
        $this->tree = $tree;
    }

    public function getStructure()
    {
        self::restructure($this->tree);
        return self::$structure;
    }

    static public function restructure(array $structure)
    {
        foreach ($structure as $k => $v)
        {
            if (isset($v['parent']) and isset($v['children']) and count($v['children']) == 1)
            {
                // only 1 child
                self::$structure[$k] = current(array_keys($v['children']));
            }
            elseif (isset($v['children']))
            {
                $keys = array_keys($v['children']);
                self::$structure[$k] = array_combine($keys, $keys); // mirror array

                //self::restructure($v['children']);
            }
            else
            {
                // no children
                self::$structure[$k] = $k;
            }
        }
    }
}



// test array

$tree = array(
    1 => array(
        'parent' => 1
    ),
    2 => array(
        'parent' => 2,
        'children' => array(
            3 => array(
                'parent' => 2
            ),
            6 => array(
                'parent' => 2,
                'children' => array(
                    10 => array(
                        'parent' => 6,
                        'children' => array(
                            4 => array(
                                'parent' => 10
                            )
                        )
                    )
                ),
            ),
        ),
    ),
    7 => array(
        'parent' => 7,
        'children' => array(
            11 => array(
                'parent' => 7
            )
        )
    ),
    14 => array(
        'parent' => 14,
        'children' => array(
            15 => array(
                'parent' => 14,
            ),
            16 => array(
                'parent' => 14,
            ),
            19 => array(
                'parent' => 14,
            ),
            20 => array(
                'parent' => 14,
            ),
            21 => array(
                'parent' => 14,
            ),
        )
    )
);

// test:
$tree = new FilterMenu($tree);
echo '<pre>'.print_r($tree->getStructure(), true);

Actual result:

Array
(
    [1] => 1
    [2] => Array
        (
            [3] => 3
            [6] => 6
        )

    [7] => 11
    [14] => Array
        (
            [15] => 15
            [16] => 16
            [19] => 19
            [20] => 20
            [21] => 21
        )

)

the desired/expected result is:

Array
(
    [1] => 1
    [2] => Array
        (
            [3] => 3
            [6] => Array
                (
                    [10] => 4 // <-- array with n-levels...
                )

        )

    [7] => 11
    [14] => Array
        (
            [15] => 15
            [16] => 16
            [19] => 19
            [20] => 20
            [21] => 21
        )

)

Here is the link to codepad that tests the class and the array.

Any help is greatly appreciated. Thanks.

like image 693
verb8 Avatar asked Nov 04 '22 04:11

verb8


1 Answers

I think you are looking for this:

function collapse(&$array) {
  foreach ($array as $k => &$v) {
    if (array_key_exists('children', $v)) {
      collapse($v['children']);
      $array[$k] = $v['children'];
    } else {
      $array[$k] = $k;
    }
  }
}

which, when called like this:

collapse($tree);
print_r($tree);

produces:

Array (
  [1]  => 1
  [2]  => Array (
            [3] => 3
            [6] => Array (
                     [10] => Array (
                               [4] => 4
                             )
                   )
          )
  [7]  => Array (
            [11] => 11
          )
  [14] => Array (
            [15] => 15
            [16] => 16
            [19] => 19
            [20] => 20
            [21] => 21
         )
)

See http://codepad.org/8atfSWGC

like image 154
Tomalak Avatar answered Nov 07 '22 23:11

Tomalak