DeiForm
DeiForm

Reputation: 664

Recursion with multidimensional array

I have been working on this for long and I got it working as I want but I think there is simpler solution.

So far I got this:

$menu = array(
    0 => (object) array(
        'cat_id'   => 1,
        'cat_parent' => 0,
        'cat_name' => 'domov',
        'cat_href' => 'domov',
        'cat_subcategories' => array()
    ),
    1 => (object) array(
        'cat_id'   => 2,
        'cat_parent' => 0,
        'cat_name' => 'clanky',
        'cat_href' => 'clanky',
        'cat_subcategories' => array(
            0 => (object) array(
                'cat_id'   => 9,
                'cat_parent' => 2,
                'cat_name' => 'apple clanky',
                'cat_href' => 'apple',
                'cat_subcategories' => array(
                    0 => (object) array(
                        'cat_id'   => 11,
                        'cat_parent' => 9,
                        'cat_name' => 'iphone clanky',
                        'cat_href' => 'iphone',
                        'cat_subcategories' => array()
                    ),
                    1 => (object) array(
                        'cat_id'   => 12,
                        'cat_parent' => 9,
                        'cat_name' => 'macbook clanky',
                        'cat_href' => 'macbook',
                        'cat_subcategories' => array()
                    )
                )
            ),
            1 => (object) array(
                'cat_id'   => 10,
                'cat_parent' => 2,
                'cat_name' => 'microsoft clanky',
                'cat_href' => 'microsoft',
                'cat_subcategories' => array()
            ),
        )
    ),
    2 => (object) array(
        'cat_id'   => 3,
        'cat_parent' => 0,
        'cat_name' => 'produkty',
        'cat_href' => 'produkty',
        'cat_subcategories' => array()
    ),
    3 => (object) array(
        'cat_id'   => 4,
        'cat_parent' => 0,
        'cat_name' => 'vyrobcovia',
        'cat_href' => 'vyrobcovia',
        'cat_subcategories' =>
            array(
                0 => (object) array(
                    'cat_id'   => 5,
                    'cat_parent' => 4,
                    'cat_name' => 'apple',
                    'cat_href' => 'apple',
                    'cat_subcategories' => array(
                        0 => (object) array(
                            'cat_id'   => 7,
                            'cat_parent' => 5,
                            'cat_name' => 'iphone',
                            'cat_href' => 'iphone',
                            'cat_subcategories' => array()
                        ),
                        1 => (object) array(
                            'cat_id'   => 8,
                            'cat_parent' => 5,
                            'cat_name' => 'macbook',
                            'cat_href' => 'macbook',
                            'cat_subcategories' => array()
                        )
                    )
                ),
                1 => (object) array(
                    'cat_id'   => 6,
                    'cat_parent' => 4,
                    'cat_name' => 'microsoft',
                    'cat_href' => 'microsoft',
                    'cat_subcategories' => array()
                ),
            )
    ),
);
function generate_menu($menu, $level = 1, $tmp_array = array())
{
    foreach($menu as $key => $c)
    {
        $menu_item = get_menu_elements($c, $level);
        $tmp_array = array_replace_recursive($tmp_array, $menu_item);

        foreach($c->cat_subcategories as $_key => $_c)
        {
            $menu_item = get_menu_elements($_c, $level+1);
            $tmp_array = array_replace_recursive($tmp_array, $menu_item);

            foreach($_c->cat_subcategories as $__key => $__c)
            {
                $menu_item = get_menu_elements($__c, $level+2);
                $tmp_array = array_replace_recursive($tmp_array, $menu_item);
            }

        }
    }

    return $tmp_array;
}

function get_menu_elements($c, $level = 1)
{

    $level_var   = "level_".($level);


    $output = array(
        $level_var => array()
    );



    $output[$level_var][$c->cat_id] = array(
        'parent' => $c->cat_parent,
        'html'   => $c->cat_name
    );

    return $output;

}

In the end I should have multidimensional array with:

array(3) {
  ["level_1"]=>
  array(4) {
    [1]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(5) "domov"
    }
    [2]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(6) "clanky"
    }
    [3]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(8) "produkty"
    }
    [4]=>
    array(2) {
      ["parent"]=>
      int(0)
      ["html"]=>
      string(10) "vyrobcovia"
    }
  }
  ["level_2"]=>
  array(4) {
    [9]=>
    array(2) {
      ["parent"]=>
      int(2)
      ["html"]=>
      string(12) "apple clanky"
    }
    [10]=>
    array(2) {
      ["parent"]=>
      int(2)
      ["html"]=>
      string(16) "microsoft clanky"
    }
    [5]=>
    array(2) {
      ["parent"]=>
      int(4)
      ["html"]=>
      string(5) "apple"
    }
    [6]=>
    array(2) {
      ["parent"]=>
      int(4)
      ["html"]=>
      string(9) "microsoft"
    }
  }
  ["level_3"]=>
  array(4) {
    [11]=>
    array(2) {
      ["parent"]=>
      int(9)
      ["html"]=>
      string(13) "iphone clanky"
    }
    [12]=>
    array(2) {
      ["parent"]=>
      int(9)
      ["html"]=>
      string(14) "macbook clanky"
    }
    [7]=>
    array(2) {
      ["parent"]=>
      int(5)
      ["html"]=>
      string(6) "iphone"
    }
    [8]=>
    array(2) {
      ["parent"]=>
      int(5)
      ["html"]=>
      string(7) "macbook"
    }
  }
}

I want to print multi-level menu recursion. I got it working with this code but in function generate_menu I had to use 3 foreach loops for cat_subcategories. When I used recursion like this:

function generate_menu($menu, $level = 1, $tmp_array = array())
{
    foreach($menu as $key => $c)
    {
        $menu_item = get_menu_elements($c, $level);
        $tmp_array = array_replace_recursive($tmp_array, $menu_item);

        if (!empty($c->cat_subcategories)) generate_menu($c->cat_subcategories, $level + 1, $tmp_array);
    }

    return $tmp_array;
}

i got only 'level_1' in output

The output which I am getting now is the same I want I just want to simplify the multiple foreach()

etc. Basicaly

level_1 - first loop of $menu level_2 - loop of cat_subcategories level_3 - loop of cat_subcategories for cat_subcategories item

Upvotes: 2

Views: 1167

Answers (3)

trincot
trincot

Reputation: 351218

You essentially need to perform a breadth-first traversal in your menu tree. For that I would suggest an iterative function instead of a recursive function, as the latter is more suitable for a depth-first traversal.

Here is the function:

function generate_menu($menu) {
    $result = [];

    $level = 1;
    while (count($menu)) {
        $queue = [];
        $items = [];
        foreach($menu as $cat) {
            $items[$cat->cat_id] = [
                "parent" => $cat->cat_parent,
                "html" => $cat->cat_name
            ];
            $queue = array_merge($queue, $cat->cat_subcategories);
        }
        $result["level_$level"] = $items;
        $level++;
        $menu = $queue;
    }
    return $result;
}

See it run on eval.in.

As this function traverses the top level of the tree, it collects all the children into $queue. Once the top level has been translated into the output (in the level_1 key), that queue will have all second level entries. This then is moved to $menu, and the process is repeated, but now with level_2. This continues until a level is reached where no more entries are found.

Upvotes: 2

junaidsidhu
junaidsidhu

Reputation: 3580

CODE TO PRINT MENU

This code will work for N-number of hierarchy

 static function printAllCategoriesAsCheckbox($arr, $d=0){

    $htmlString = "";

    if (is_array($arr)){
        foreach($arr as $category){

            $htmlString = $htmlString . '<div><input style="margin-left: ' . 30*$d . 'px;" value="'.$category->id.'" class="category-input" type="checkbox" name="category_id[]">';

            $htmlString = $htmlString . ' <label for="category_'.$category->id.'">' . $category->name . '</label></div>';


            if (is_array($category['childs'])){
                $htmlString = $htmlString . ItemCategory::printAllCategoriesAsCheckbox($category['childs'], $d+1);
            }
        }
    }

    return $htmlString;
}

item list

Upvotes: 0

Kryštof Řeh&#225;ček
Kryštof Řeh&#225;ček

Reputation: 2483

I've made some time ago this function. It could help you.

I've got an array where $arr[actual item][parental id]

function getChild($id, $result, $count) {
    for( $i = 0; $i < sizeof($result); $i ++) {
        if( $result[$i][2] == $id) {
            getChild($result[$i][0], $result, $count + 1);
        }
    }
}

EDIT

In my case, where all the items in the one-dimensional array, but with the hierarchy of n-dimensional array depended on the parental id.

Upvotes: 0

Related Questions