it-swarm.com.de

Erstellen Sie einen Baum aus einem flachen Array in PHP

Ich habe um das Internet geschaut und noch nicht ganz gefunden, was ich suche. Ich habe eine flache Anordnung, wobei jedes Element, das einen ‚id‘ und ein ‚parent_id‘. Jedes Element wird nur ein Elternteil, kann aber mehrere Kinder haben. Wenn die parent_id = 0, wird ein Root-Ebene Punkt betrachtet. Ich versuche, meine flache Array in einen Baum zu erhalten. Die anderen Beispiele, die ich gefunden habe, kopieren nur das Element in das übergeordnete Element, aber das Original ist noch vorhanden.

EDIT

Jedes Element des Startarrays wird aus einer separaten XML-Datei gelesen. Die Datei selbst wird ‚0‘ als Wert für parent_id, wenn es nicht einen Elternteil hat. Die Tasten sind eigentlich Saiten.

Es tut mir leid für die Verwirrung vorhin. Hoffentlich ist das klarer:

/ EDIT

Mein Start-Array:

 Array 
 (
 [_319_] => Array 
 (
 [Id] => 0 
 [Parent_id] => 0 
) 
 
 [_320_] => Array 
 (
 [id] => _320 _ 
 [parent_id] => 0 
) 
 
 [_321_] => Array 
 (
 [Id] => _321 _ 
 [Parent_id] => _320 _ 
) 
 
 [_322_] => Array 
 (
 [Id] => _322 _ 
 [Parent_id] => _321 _ 
) 
 
 [_323_] => Array 
 (
 [id] => _323 _ 
 [parent_id] => 0 
) 
 
 [_324_] => Array 
 (
 [Id] => _324 _ 
 [Parent_id] => _323 _ 
) 
 
 [_325_] => Array 
 (
 [Id] => _325 _ 
 [Parent_id] => _320 _ 
) 
)

Das resultierende Array, nachdem der Baum erstellt wurde:

 Array 
 (
 [_319_] => Array 
 (
 [Id] => _319 _ 
 [Parent_id] => 0 
) 
 
 [_320_] => Array 
 (
 [id] => _320 _ 
 [parent_id] => 0 
 [Kinder] => Array 
 (
 [_321_] => Array 
 (
 [Id] => _321 _ 
 [parent_id] => _320 _ 
 [children] => Array 
 (
 [_322_] => Array 
 (
 [id] = > _322 _ 
 [Parent_id] => _321 _ 
) 
) 
) 
 [_325_] => Array 
 (
 [Id] => _325 _ 
 [Parent_id] => _320 _ 
) 
) 
 [_323_] => Array 
 (
 [Id] => _323 _ 
 [Parent_id] => 0 
 [Children] => Array 
 (
 [_324_] => Array 
 (
 [Id] => _324 _ 
 [Parent_id] => _323 _ 
) 
) 
) 

Jede Hilfe/Anleitung ist sehr zu schätzen!

Code, den ich bisher habe:

 
 Funktion BuildTree (array & $ Elemente, $ parentId = 0) {
 $ Zweig = array (); [. .____] [. .____] foreach ($ Elemente als $ element) {
 if ($ element ['parent_id'] == $ parentId) {
 $ children = $ this-> buildTree ($ elements, $ element ['id']) 
 if ($ Kinder) {
 $ Element [ 'Kinder'] = $ Kinder; 
}; 
 $ Zweig [] = $ Element; 
} 
} 
 
 return $ branch; 
} 
 
34
DSkinner

Du hast das unset() dort drin vergessen, Bruder.

function buildTree(array &$elements, $parentId = 0) {
    $branch = array();

    foreach ($elements as $element) {
        if ($element['parent_id'] == $parentId) {
            $children = buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[$element['id']] = $element;
            unset($elements[$element['id']]);
        }
    }
    return $branch;
}
51
n0nag0n

Die Lösung von ImmortalFirefly funktioniert, rettet jedoch, wie mrded betont, nicht die ersten Eltern ohne Kinder. Ich habe die Funktion bearbeitet dieses Problem zu beheben:

function buildTree(array &$elements, $parentId = 0) {

    $branch = array();

    foreach ($elements as &$element) {

        if ($element['parent_id'] == $parentId) {
            $children = buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[$element['id']] = $element;
            unset($element);
        }
    }
    return $branch;
}
27
SteveEdson

Das funktioniert bei mir:

$index=array();
$tree=array();
foreach ($ori as $key=>$var) {
  $var=array_shift($ori);
  if ($var['id']==0) $var['id']=$key;
  if ((string)$var['parent_id']==='0') {
    $tree[$key]=$var;
    $index[$key]=&$tree[$key];
  } else if (isset($index[$var['parent_id']])) {
    if (!isset($index[$var['parent_id']]['children'])) $index[$var['parent_id']]['children']=array();
    $index[$var['parent_id']]['children'][$key]=$var;
    $index[$key]=&$index[$var['parent_id']]['children'][$key];
  } else {
    array_Push($ori,$var);
  }
}
unset($index);
print_r($tree);
6
Eugen Rieck

Ich kann die Logik sehen, außer im Ergebnis:

Array
(
    [0] => Array
        (
            [id] => 0
            [parent_id] => 0
        )

    [1] => Array
        (
            [id] => 1
            [parent_id] => 0
        )

IMHO ist parent_id = o, sollte nicht [1] sein, ein Kind von [0] hier?

Wie auch immer, Hinweise zur Rettung:

$tree = array();
foreach($inputarray as $item){
     if(!isset($tree[$item['id']])) $tree[$item['id']] = array();
     $tree[$item['id']] = array_merge($tree[$item['id']],$item);
     if(!isset($tree[$item['parent_id']])) $tree[$item['parent_id']] = array();
     if(!isset($tree[$item['parent_id']]['children'])) $tree[$item['parent_id']]['children'] = array();
     $tree[$item['parent_id']]['children'][] = &$tree[$item['id']];
}
$result = $tree[0]['children'];
unset($tree);
print_r($result);

Weil du 0, da beide eine ‚magische‘ Zahl als root missbraucht haben, und eine bestehende ID, haben wir nun Rekursion in der id = 0 Zweig. Das Hinzufügen von if($item['parent_id']!=$item['id']) vor $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; Könnte das verhindern, aber es ist nicht schön.

3
Wrikken

Es ist möglich, das Quell-Array etwas anders zu konstruieren. Verwenden Sie dazu die folgende Funktion (parent_id, id, title):

$q = mysql_query("SELECT id, parent_id, name FROM categories");
while ($r = mysql_fetch_row($q)) {
  $names[$r[0]] = $r[2];
  $children[$r[0]][] = $r[1];
 }

function render_select($root=0, $level=-1) {
  global $names, $children;
  if ($root != 0)
    echo '<option>' . strrep(' ', $level) . $names[$root] . '</option>';
  foreach ($children[$root] as $child)
    render_select($child, $level+1);
}

echo '<select>';
render_select();
echo '</select>';
  1. Effizientere Hierarchie-System
2
Gigamegs

Obwohl dies eine alte Frage ist, werde ich meine Antwort hier posten:

/* assuming top level pid = 0 */
$rows = array (
    array ( 'id' => 1, 'pid' => 0 ),
    /* ... */
);

/* make id become array key */
$rows = array_column ( $rows, null, 'id' ); 

foreach ( $rows as $key => $val ) {
    if ( $val ['pid'] ) {
        if ( isset ( $rows [$val ['pid']] )) {
            $rows [$val ['pid']]['children'][] = &$rows [$key];
        }
    }
}

foreach ( $rows as $key => $val ) {
    if ( $val ['pid'] ) unset ( $rows [$key] );
}

array_column Ist PHP 5.5, aber Sie können Ihre eigenen leicht zu machen.

2
Inglis Baderson

Der Code von SteveEdson funktioniert einwandfrei, außer wenn das übergeordnete Element eines Elements in der ursprünglichen Datenstruktur nicht vorhanden ist. Hier ist meine Lösung für die (aber es entfernt „parent_id“ von Elementen, die oder nicht akzeptabel sein können):

function buildTree(array &$elements, $parentId = 0)
{
    $branch = array();
    foreach ($elements as &$element) {
        if ($element["parent_id"] != null && $elements[$element["parent_id"]] == null)
            unset($element["parent_id"]);        
        if ($element['parent_id'] == $parentId) {
            $children = buildTree($elements, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[$element['id']] = $element;
            unset($element);
        }
    }
    return $branch;
}
1
Arne M

Sie möchten versuchen, hierarchische Daten in MySQL zu speichern und zu laden, da dies einige Probleme lösen sollte. Ich gehe davon aus, dass die erste Array-Daten direkt aus der Datenbank repräsentiert?

Es sieht aus wie Sie versuchen, das adjacency Modell zu verwenden, um Ihre Daten in die Hierarchiestruktur zu organisieren. Es gibt auch andere Möglichkeiten, um diese mit Verschachtelung zu erreichen. Wenn Sie diese Daten nicht aus einer Datenbank nehmen, dann kann dies nicht so nützlich sein.

Dieser Link sollte Ihnen helfen: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

1
Daniel West

Hier ist meine Lösung, funktioniert im Idealfall, wenn wir davon ausgehen, dass die Top-Level-parent_id = 0:

function MakeTree($arr){
    $parents_arr=array();
    foreach ($arr as $key => $value) {
        $parents_arr[$value['pid']][$value['id']]=$value;
    }
    $tree=$parents_arr['0'];
    $this->createTree($tree, $parents_arr);
    return $tree;
}
function createTree(&$tree, $parents_arr){
    foreach ($tree as $key => $value) {
        if(!isset($value['children'])) {
            $tree[$key]['children']=array();
        }
        if(array_key_exists($key, $parents_arr)){
            $tree[$key]['children']=$parents_arr[$key];
            $this->createTree($tree[$key]['children'], $parents_arr);
        }
    }
}
0
user628176

Sauber, kurz und frei von Ballast. Array von Arrays zum Baum:

class Mother {
    private $root;
    public function treeInit($array)
    {
        $this->root = new Child();
        foreach($array as $value){
            $this->root->treeClimb(array_reverse($value));
        }
        return $this->root;
    }
}

class Child {
    private $children = [];
    public function treeClimb($arr)
    {
        if(count($arr) > 0) {
            $childTmp = array_pop($arr);
            if(!key_exists($childTmp,$this->children))
            {
                $this->children[$childTmp] = new Child();
            }
        $this->children[$childTmp]->treeClimb($arr);
        }
    }
}

$array = array(array('obst','banae','krumm','gelb'),
                    array('obst','beere','him'),
                    array('obst','beere','brom'),
                    array('obst','banae','gerade'),
                    array('veg','carot','gerade'));

$obj = new Mother();
var_dump($obj->treeInit($array));

Dies ist meine Lösung, kopieren und optimieren Sie andere Lösungen.

function buildTree(array &$elements, $parentId = 0) {
    $branch = array();
    foreach ($elements as $key => $element) {
        if ($element['parent_id'] == $parentId) {
            $children = $this->buildTree($elements, $key);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[$key] = $element;
            unset($elements[$key]);
        }
    }
    return $branch;
}
0
touzas

Ich hatte eine ähnliche Lösung wie @ eugen-rieck und wollte sie teilen. Ich nannte $branches mein Array von Indizes, obwohl.

$tree = [];
$branches = [];

while (!empty($input)) {
    $beforeCount = count($input);

    foreach ($input as $id => $item) {
        $pid = $item['parent_id'];

        if (isset($branches[$pid])) {
            $branches[$pid]['children'][$id] = $item;
            $branches[$id] = &$branches[$pid]['children'][$id];
            unset($input[$id]);
        }
    }

    if ($beforeCount === count($input)) {
        $firstItem = array_shift($input);
        $id = $firstItem['id'];
        $tree[$id] = $firstItem;
        $branches[$id] = &$tree[$id];
    }
}
0
hoorider