1

everyone!

I'm stuck trying write a recursive function. =( This is my function, which, as I expected, will turn my plain array into multidimensional one.

function BuildTree($src, $index=0) {
    foreach ($src as $index=>$curentItem) {
        $nextItem = (is_array($src[$index+1]))?$src[$index+1]:false;
        unset($src[$index]);
        if ($nextItem['d']==$curentItem['d']) $brunchArray[] = $curentItem['n'];
        if ($nextItem['d']>$curentItem['d']) $brunchArray['childrens'] = BuildTree($src, $index);
        if (!$nextItem || $nextItem['d']<$curentItem['d']) return $brunchArray;
    }
}

Input array is something like this:

$input = array (
array(
        'n' => 'Articles',
        'd' => 0
    ),
array(
        'n' => 'Article 1',
        'd' => 1
    ),
array(
        'n' => 'Books',
        'd' => 0
    ),
array(
        'n' => 'Book 1',
        'd' => 1
    ),
array(
        'n' => 'Book 2',
        'd' => 1
    ),
array(
        'n' => 'Chapter 1',
        'd' => 2
    ),
array(
        'n' => 'Chapter 2',
        'd' => 2
    )
);

And I want it to be converted into this:

array (
    array(
            'n' => 'Articles',
            'd' => 0,
            'childrens' => array (
                array(
                        'n' => 'Article 1',
                        'd' => 1
                    ),
            )
        ),
    array(
            'n' => 'Books',
            'd' => 0,
            'childrens' => array (
                array(
                        'n' => 'Book 1',
                        'd' => 1
                    ),
                array(
                        'n' => 'Book 2',
                        'd' => 1
                        'childrens' => array (
                            array(
                                    'n' => 'Chapter 1',
                                    'd' => 2
                                ),
                            array(
                                    'n' => 'Chapter 2',
                                    'd' => 2
                                )
                        )
                    )
            )
        )
)

I already spent three hours trying to solve this. =( Any help will be highly appreciated!

5
  • And how your program should guess which item is children of which one? Commented Mar 19, 2013 at 10:32
  • they are already sorted in right order Commented Mar 19, 2013 at 10:35
  • Does it have to be recursive? Commented Mar 19, 2013 at 10:38
  • I supposed so, because we do not know how many depth levels will be in input array Commented Mar 19, 2013 at 10:41
  • Challenge accepted :D Commented Mar 19, 2013 at 10:58

2 Answers 2

1

Here is a solution without recursion:

function convert($arr) {
    $stack = array();
    $output = array();
    $arr[] = array('d' => -1); // Dummy record at the end
    for($i = 0; $i < count($arr); $i++) {
        while(!empty($stack) && $stack[count($stack) - 1]['d'] > $arr[$i]['d']) {
            $current_d = $stack[count($stack) - 1]['d'];
            $children = array();
            while(!empty($stack) && $stack[count($stack) - 1]['d'] >= $current_d) {
                $children[] = array_pop($stack);
            }
            $children = array_reverse($children);
            if(empty($stack)) {
                foreach($children as $child) {
                    $output[] = $child;
                }
            } else {
                $stack[count($stack) - 1]['children'] = $children;
            }
        }
        $stack[] = $arr[$i];
    }
    return $output;
}

$input = array (
array(
        'n' => 'Articles',
        'd' => 0
    ),
array(
        'n' => 'Article 1',
        'd' => 1
    ),
array(
        'n' => 'Books',
        'd' => 0
    ),
array(
        'n' => 'Book 1',
        'd' => 1
    ),
array(
        'n' => 'Book 2',
        'd' => 1
    ),
array(
        'n' => 'Chapter 1',
        'd' => 2
    ),
array(
        'n' => 'Chapter 2',
        'd' => 2
    )
);

var_dump(convert($input));
Sign up to request clarification or add additional context in comments.

3 Comments

Cool! I'm surprised that it can be done this way, but you proved it. I'll try to compare which one is faster some while later.
How can I mark both answers as correct in this site? Is it possible?
Unfortunately you can't, but you must keep your question in mind: "I'm stuck trying write a recursive function" :( Just up vote the answers such to pass on the recognition :D
0

Using the same $input:

$output = array();

function buildTree(&$input, &$output, &$current, $level = 0) {
    if(!$input)
        return;
    $next = array_shift($input);
    if($next['d'] == $level) {
        $current[] = $next;
        return buildTree($input, $output, $current, $level);
    } else if($next['d'] == $level + 1) {
        $current[count($current) - 1]['childrens'] = array($next);
        return buildTree($input, $output, $current[count($current) - 1]['childrens'], $level + 1);
    } else {
        $output[] = $next;
        return buildTree($input, $output, $output, 0);
    }
}

buildTree($input, $output, $output);

var_dump($output);

3 Comments

Thank you :D I enjoyed solving that one! Good question :)
@aram90 posted a "non recursive" solution downhere. Its also works fine. It'll be interesting to compare which one is faster.
Well this isn't traditional recursion like the typical Fibonacci examples, so it's not exponential time. It is, in fact, linear - as is his - so the difference won't be very noticeable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.