php通过父ID将数组转换为多维数组

时间:2014-12-08 15:03:27

标签: php arrays multidimensional-array

我有一个带有stdclasses的一维数组,这些对象有一个名字和一个" abh"属性。 现在我想得到一个像多维数组的树视图。让我们说我的数组看起来像这样:

$ar = array(
    (object)array("name" => "Test1","otherstuff"=>array(),"abh"=>""),
    (object)array("name" => "Test2","otherstuff"=>array(),"abh"=>"Test1"),
    (object)array("name" => "Test3","otherstuff"=>array(),"abh"=>"Test1"),
    (object)array("name" => "Test4","otherstuff"=>array(),"abh"=>"Test1"),
    (object)array("name" => "Test5","otherstuff"=>array(),"abh"=>"Test1"),
    (object)array("name" => "Test6","otherstuff"=>array(),"abh"=>"Test5"),
    (object)array("name" => "Test7","otherstuff"=>array(),"abh"=>"Test5"),
    (object)array("name" => "Test8","otherstuff"=>array(),"abh"=>array("Test5","Test7")),
    (object)array("name" => "Test9","otherstuff"=>array(),"abh"=>"Test8"),
    (object)array("name" => "Test10","otherstuff"=>array(),"abh"=>"Test6"),
    (object)array("name" => "Test11","otherstuff"=>array(),"abh"=>"Test9"),
);

数据来自之前调用的函数,不是来自数据库。结果是这样的:

Array
(
[0] => stdClass Object
    (
        [name] => Test1
        [otherstuff] => Array
            (
            )

        [abh] => 
    )

[1] => stdClass Object
    (
        [name] => Test2
        [otherstuff] => Array
            (
            )

        [abh] => Test1
    )
[...]
)

所以现在,我希望这个数组将被" abh"属性。第一个" abh"是空的,它的根,所有其他人将成为它的孩子。所以该功能必须添加一个"孩子"属于主如果它有孩子。但现在这个是特殊类型,因为" abh"可以是一个阵列本身,并重新设置为n父母。在上面的例子中,Test8应该是Test5和Test7(克隆)的孩子。

我尝试使用递归函数处理此问题并在foreach中循环。在那里它检查一个元素的abh而不是父母存在,但不工作。 array_filter()doenst就像我想要的那样。

所以,我想要这个结果:

Array
(
    [Test1] => stdClass Object
        (
            [name] => Test1
            [otherstuff] => Array()
            [abh] => 
            [childs] => Array
                (
                    [Test2] => stdClass Object
                        [...] and so on
                )
        )
)

有关于此的任何想法? 我也不知道多少"水平"返回的数组将具有,即多少输入对象和" abh" -assignes存在。秒是" abh"数组最多可以有10个父母"。

感谢您的帮助!


as as requesttet 我的非工作原型" sorter"

function checkABH(&$return,&$ar,$deph) {

    // clone all with array-abh
    $count = count($ar);
    for($x=0;$x<$count;$x++) {#$ar as$key=>$val) {
        if(is_array($ar[$x]->abh)) {
            $clone = $ar[$x];
            foreach($ar[$x]->abh as$abh) {
                #echo "<br>$x @@ $abh";
                $clone->abh = $abh;
                $ar[]       = $clone;
                #echo '<pre>'.print_r($clone,true).'</pre>';
            }
            // delete array-abh-element
            unset($ar[$x]);
        }
    }

    echo '<pre>'.print_r($ar,true).'</pre>';
    echo '</div>';
    echo '<div style="float:left;width:auto;margin:0px 10px;"><h3>Result:</h3>';

    // pass to sorter
    checkABH_a($return,$ar,$deph);
}

function checkABH_a(&$return,&$ar,$deph) {

    $test_abhs = array();

    foreach($ar as$key=>$val) {

        $val->childs = array();

        if(isset($return[$deph])&&isset($return[$deph]->name)&&$val->abh==$return[$deph]->name) {
            $return[$deph]->childs[] = $val;
            unset($ar[$key]);
        } elseif($val->abh==$deph) {
            $return[$val->abh] = $val;
            unset($ar[$key]);
        } else {
            $test_abhs[] = $val->abh;
        }
    }

    if(count($test_abhs)>0) {
        $test_abhs = array_unique($test_abhs);
        #echo '<pre>'.print_r($test_abhs,true).'</pre>';
        foreach($test_abhs as$abh) {
            checkABH_a($return,$ar,$abh);
        }
    }
}

echo '<div style="float:left;width:260px;border-right:1px solid #cccccc;margin:0px 10px;"><h3>Input</h3>';
echo '<pre>'.print_r($ar,true).'</pre>';
echo '</div>';
echo '<div style="float:left;width:260px;border-right:1px solid #cccccc;margin:0px 10px;"><h3>Cloned:</h3>';
$return = array();
checkABH($return,$ar,"");
echo'<pre>'.print_r($return,true).'</pre>';
echo '</div>';

1 个答案:

答案 0 :(得分:1)

这些递归树没有变得容易,添加了“多父”要求是什么; - /无论如何,它看起来仍然很有趣......

我不会在这里记录所有代码,因为我认为我已经对它进行了充分的评论。

注意:

  • 将“多个父母”转换(复制)到各个条目,以便“insertNode”功能更容易理解。
  • 而不是使用'stdClass'我创建了一个名为'TreeNode'的类,因为我可能想稍后添加方法。

<强> Working version of the code at Viper-7.com using PHP 5.3.18

有关代码的任何查询然后发表评论,我会尝试回答他们。

<?php // https://stackoverflow.com/questions/27360813/php-convert-array-to-multidimensional-array-by-parent-id

$ar = array(
    (object) array("name" => "Test1", "otherstuff"=>array('parent is Test1'), "abh"=>""),
    (object) array("name" => "Test2", "otherstuff"=>array('parent is Test1'), "abh"=>"Test1"),
    (object) array("name" => "Test3", "otherstuff"=>array('parent is Test1'), "abh"=>"Test1"),
    (object) array("name" => "Test4", "otherstuff"=>array('parent is Test1'), "abh"=>"Test1"),
    (object) array("name" => "Test5", "otherstuff"=>array('parent is Test1'), "abh"=>"Test1"),
    (object) array("name" => "Test6", "otherstuff"=>array('parent is Test5'), "abh"=>"Test5"),
    (object) array("name" => "Test7", "otherstuff"=>array('parent is Test5'), "abh"=>"Test5"),
    (object) array("name" => "Test8", "otherstuff"=>array('parent is Test5 AND Test7'), "abh"=>array("Test5", "Test7")),
    (object) array("name" => "Test9", "otherstuff"=>array('parent is Test8'), "abh"=>"Test8"),
    (object) array("name" => "Test10", "otherstuff"=>array('parent is Test6'), "abh"=>"Test6"),
    (object) array("name" => "Test11", "otherstuff"=>array('parent is Test9'), "abh"=>"Test9"),
);


/*
 * The requirement is that for any child then the parent must be in the tree already.
 */

// Convert those parent with 'arrays of parents' into individual entries as it will make the insert
// easier to understand.

// i will also convert all the input into a 'TreeNode' class while i am doing this pass down the input. 
// i can add some methods later if i wish.

// i will also get the root of the tree while i am doing this...
$rootNode = new TreeNode(array_shift($ar));

$treeNodeList = array();
foreach($ar as $node) {
    if (is_array($node->abh)) { // generate duplicate nodes
        foreach($node->abh as $parentName) {
            $node->abh = $parentName; // make it an ordinary node
            $treeNodeList[] = new TreeNode($node);
        }
        continue;
    }
    $treeNodeList[] = new TreeNode($node);
}

// var_dump($ar, $rootNode, $treeNodeList);

// Ok, we now have a node list in the appropriate order - let us build the tree

/**
 * This is a 'multiway' tree .i.e. there can be any number of 'child' nodes
 *                                 for any parent
 * Usual rules:
 *   o The parent MUST be in the tree already.
 *   o Children are added, by searching from the root of the tree, in this version
 *
 */

// the output will be here
$theTree = array($rootNode->name => $rootNode);

foreach ($treeNodeList as $childNode) { // add it
    $inserted = insertNode($rootNode, $childNode);
    if (!$inserted) {
      var_dump('Unable to insert:', $childNode, ' in tree:', $rootNode);
      die('i am here: '. __FILE__.__LINE__);
    }
}

// show the tree
echo '<pre>';
   print_r($theTree);
echo '</pre>';

exit;
// --------- end of processing -------------

/**
 * Insert the node in the tree
 *
 * @param TreeNode $parent
 * @param TreeNode $newChild
 */
function insertNode(TreeNode &$parent, TreeNode $newChild) {
    if ($newChild->abh === $parent->name) { // add it to the current parent
        $parent->children[$newChild->name] = $newChild; // add child
        return true;
    }

    // check the children
    foreach($parent->children as $newParent) {
       if (insertNode($newParent, $newChild)) {
          return true;
       }
    }
    return false; // unable to insert child in the tree
}

// -----------------------------------------------------------------------
/**
 * treeNode: (Data and Relationships)
 *   nodeId:            'name'
 *   nodeData:          'otherstuff'
 *   nodeParentList:    'abh' - may be a list of parents.
 *                          Note: In this version of the code: All the parents
 *                                MUST be in the tree already.
 *   children:          array of treeNode - recursive structure
 */

// i will make the properties all public to make it easier to debug.

class TreeNode  {
    public $name = '';
    public $otherstuff = array();
    public $abh = '';
    public $children = array(); // list of child nodes

    public function __construct(stdClass $node)
    {
        $this->name = $node->name;
        $this->otherstuff = $node->otherstuff;
        $this->abh = $node->abh;
    }
} // class end --------------------------