Creating a recursive array in PHP

I am trying to create a recursive array based on string length: string length is node level. It actually builds a Yii based tree structure. Here's an example ...

I have a list of strings:

Array
(
    [0] => A
    [1] => C
    [2] => CC
    [3] => CCC
    [4] => P
    [5] => PP
    [6] => PPP
    [7] => PPPE
    [8] => PS
    [9] => PSA
)

      

And I want to sort them like this:

Array
(
    [0] => Array
        (
            [text] => A
        )

    [1] => Array
        (
            [text] => C
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => CC
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [text] => CCC
                                        )
                                )
                        )
                )
        )

    [2] => Array
        (
            [text] => P
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => PP
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [text] => PPP
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [text] => PPPE
                                                        )
                                                )
                                        )
                                )
                        )

                    [1] => Array
                        (
                            [text] => PS
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [text] => PSA
                                        )
                                )
                        )
                )
        )
)

      

I know I need to figure something out with recursive functions, but I just don't know how to do it, even though I've been trying for days ... Has someone done something similar? Many thanks...

+3


source to share


4 answers


This should give you what you want:



function &createNodeFromText(&$tree, $text)
{
    if(strlen($text) > 1) {
        //Make sure we have created the parent node(s) we need:
        $parent = &createNodeFromText($tree, substr($text, 0, -1));

        //Create a new tree level for the current node if needed:
        if(!isset($parent["children"])) {
            $parent["children"] = array();
        }
        $currentLevel = &$parent["children"];
    }
    else {
        //New root node:
        $currentLevel = &$tree;
    }

    //Look for the requested node..
    $nodeText = $text;
    $currentNode = null;
    for ($i = 0; $i < count($currentLevel); ++$i) {

        $node = &$currentLevel[$i];
        if($node["text"] === $nodeText)
        {
            $currentNode = &$node;
            break;
        }
    }
    //..and create a new one only if we have to:
    if($currentNode === null) {
        $currentNode = array("text" => $nodeText);
        $currentLevel[] = &$currentNode;
    }

    return $currentNode;
}


$source = array("A", "C", "CC", "CCC", "P", "PP", "PPP", "PPPE", "PS", "PSA");
$final = array();
foreach($source as $s) {
    createNodeFromText($final, $s);
}

print_r($final);

      

+2


source


Your question is peculiar and I couldn't help but try to wrap my head around.

I don't think you'll find that recursion will solve your problem. The reason is that in order to do some recursion, you have to name your function yourself. By the time the function is called by itself, you've most likely done some work on your original array, making it (almost) necessary to pass what's left of the array by reference. The problem in your case is that you want to rebuild your array in a way that won't be reached by recursion. (At least without creating a nasty mess of if / else branches to handle your conditions.)

In your situation, I suggest that you work on a class that can be classified as you wish based on a number of conditions. Your problem requires you to keep track of some overhead in order to rebuild the array as you would like. You need to check (but not limited to) things like:

  • Index created for text

    .
  • Index created for children

    .
  • Whether you want to assign a graded item text

    or children

    .
  • Am I at the correct level in the array or do I need to step back?

All of these conditions, combined with your sorting requirements, make this task the most appropriate for the class. Your class can have different fields that will keep track of all of these conditions and allow any recursion you use to become more efficient. (The good news is that if you create a class like this and keep the inner workings inside the class, it is easily portable to other projects.)



Anyway, here's a recursive function that will almost get what you want.

<?php

$source = array("A", "C", "CC", "CCC", "P", "PP", "PPP", "PPPE", "PS", "PSA");

$rebuilt = array();
function categorize(&$array)
{
    $newArray = array();
    if(isset($array[0])) {
        $newArray["text"] = $array[0];
        array_shift($array);
        if(isset($array[0]) && (strlen($newArray["text"]) < strlen($array[0]))) {
            if(substr_compare($array[0], $newArray["text"], 0, strlen($newArray["text"])) == 0) {
                $newArray["children"] = array(categorize($array));
            }
        }
    }
    return $newArray;
}

//Usage:

$sorted = array();
while(count($source) > 0) {
    $sorted[] = categorize($source);
}
print_r($sorted);

?>

      

The output will be:

Array
(
    [0] => Array
        (
            [text] => A
        )

    [1] => Array
        (
            [text] => C
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => CC
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [text] => CCC
                                        )

                                )

                        )

                )

        )

    [2] => Array
        (
            [text] => P
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => PP
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [text] => PPP
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [text] => PPPE
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

    [3] => Array
        (
            [text] => PS
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => PSA
                        )

                )

        )

)

      

+2


source


<?php

     class ArrayRecursiver
    {
        private $baseArray = array();
        private $tmpArray = array();

        private function hasParentNode($node)
        {
            if(strlen($node) > 1)
                return true;
            else
                return false;

        }

        private function getParentNode($node)
        {
            return substr($node, 0, -1);
        }

        private function createNode($node, $existChild = null)
        {
            $_tmp = array("text" => $node);
            if (!empty($existChild))
                $_tmp = array("text"=> $node, "children" => $existChild);

            if ( $this->hasParentNode($node) )
            {
                return $this->createNode($this->getParentNode($node), $_tmp);
            }
            else
            {
                return $_tmp;
            }
        }

        public function setBase($a)
        {
            $_tmp = $a;
            usort($_tmp, function($a, $b) {
                if($a==$b) return 0;
                return $a < $b?1:-1;
            });

            $this->baseArray = $_tmp;
        }

        public function makeAWish()
        {
            $prev = null;
            foreach ($this->baseArray as $key => $node)
            {
                $_tmp = $this->createNode($node);
                    $this->tmpArray[]=  $_tmp;

            }
            return $this->tmpArray;
        }
    }// end class ArrayRecursiver

    $badArray = array(
        "A","C","CC","CCA","P","PP","PPP","PPPE","PS","PSA"
    );


        echo "<pre>";

        $worker = new ArrayRecursiver();
        $worker->setBase($badArray);
        print_r($worker->makeAWish());

        echo "</pre>";

      

This is almost what you need;) I say almost;) Need to rebuild the returned array now, I hope this helps you

+1


source


I've actually tried something like this:

$final = array();
$fi = 0;

foreach ($data as $id => $key) {
    if (strlen($key) == 1) {
        //Main node
        $final[$fi] = array('text'=>$key);
        $fi++;
    } else {
        if (empty($final[$fi-1]['children']))
            $final[$fi-1]['children'] = array();
        $final[$fi-1]['children'][] = array('text'=>$key);
    }
}

      

But it lacks recursiveness, I guess ... Anyway, it gives me this array, which I am not looking for:

Array
(
    [0] => Array
        (
            [text] => A
        )

    [1] => Array
        (
            [text] => C
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => CC
                        )
                    [1] => Array
                        (
                            [text] => CCC
                        )
                )
        )

    [2] => Array
        (
            [text] => P
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => PP
                        )
                    [1] => Array
                        (
                            [text] => PPP
                        )
                    [2] => Array
                        (
                            [text] => PPPE
                        )
                    [3] => Array
                        (
                            [text] => PS
                        )
                    [4] => Array
                        (
                            [text] => PSA
                        )
                )
        )
)

      

0


source







All Articles