Ich möchte eine Funktion schreiben, die ein Array von Seiten / Kategorien (aus einem flachen Datenbankergebnis) verwendet und ein Array von verschachtelten Seiten- / Kategorieelementen basierend auf den übergeordneten IDs generiert. Ich würde dies gerne rekursiv machen, damit jede Ebene der Verschachtelung durchgeführt werden kann.
Beispiel: Ich rufe alle Seiten in einer Abfrage ab, und so sieht die Datenbanktabelle aus
+-------+---------------+---------------------------+
| id | parent_id | title |
+-------+---------------+---------------------------+
| 1 | 0 | Parent Page |
| 2 | 1 | Sub Page |
| 3 | 2 | Sub Sub Page |
| 4 | 0 | Another Parent Page |
+-------+---------------+---------------------------+
Und dies ist das Array, mit dem ich am Ende in meinen Ansichtsdateien arbeiten möchte:
Array
(
[0] => Array
(
[id] => 1
[parent_id] => 0
[title] => Parent Page
[children] => Array
(
[0] => Array
(
[id] => 2
[parent_id] => 1
[title] => Sub Page
[children] => Array
(
[0] => Array
(
[id] => 3
[parent_id] => 1
[title] => Sub Sub Page
)
)
)
)
)
[1] => Array
(
[id] => 4
[parent_id] => 0
[title] => Another Parent Page
)
)
Ich habe fast jede Lösung gesucht und ausprobiert, auf die ich gestoßen bin (es gibt viele hier auf Stack Overflow, aber ich hatte kein Glück, etwas Generisches zu bekommen, das sowohl für Seiten als auch für Kategorien funktioniert.
Hier ist der nächste, den ich bekommen habe, aber es funktioniert nicht, weil ich die Kinder dem Elternteil der ersten Ebene zuordne.
function page_walk($array, $parent_id = FALSE)
{
$organized_pages = array();
$children = array();
foreach($array as $index => $page)
{
if ( $page['parent_id'] == 0) // No, just spit it out and you're done
{
$organized_pages[$index] = $page;
}
else // If it does,
{
$organized_pages[$parent_id]['children'][$page['id']] = $this->page_walk($page, $parent_id);
}
}
return $organized_pages;
}
function page_list($array)
{
$fakepages = array();
$fakepages[0] = array('id' => 1, 'parent_id' => 0, 'title' => 'Parent Page');
$fakepages[1] = array('id' => 2, 'parent_id' => 1, 'title' => 'Sub Page');
$fakepages[2] = array('id' => 3, 'parent_id' => 2, 'title' => 'Sub Sub Page');
$fakepages[3] = array('id' => 4, 'parent_id' => 3, 'title' => 'Another Parent Page');
$pages = $this->page_walk($fakepages, 0);
print_r($pages);
}
Antworten:
Einige sehr einfache, generische Baumbauten:
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; } } return $branch; } $tree = buildTree($rows);
Der Algorithmus ist ziemlich einfach:
0
/ nichts /null
/ was auch immer).parent_id
eines Elements mit der aktuellen übergeordneten ID übereinstimmt, die Sie in 1. erhalten haben, ist das Element ein untergeordnetes Element des übergeordneten Elements. Tragen Sie es in Ihre Liste der aktuellen Kinder ein (hier :)$branch
.children
Element hinzu.Mit anderen Worten, eine Ausführung dieser Funktion gibt eine Liste von Elementen zurück, die untergeordnete Elemente der angegebenen übergeordneten ID sind. Rufen Sie es mit auf
buildTree($myArray, 1)
, es wird eine Liste von Elementen zurückgegeben, die die übergeordnete ID 1 haben. Anfangs wird diese Funktion aufgerufen, wobei die übergeordnete ID 0 ist, sodass Elemente ohne übergeordnete ID zurückgegeben werden, die Stammknoten sind. Die Funktion ruft sich rekursiv auf, um Kinder von Kindern zu finden.quelle
$elements
Array weitergegeben wird. Bei kleinen Arrays spielt das kaum eine Rolle, bei großen Datenmengen sollten Sie jedoch das bereits übereinstimmende Element entfernen, bevor Sie es weitergeben. Das wird allerdings etwas chaotisch, deshalb habe ich es zum leichteren Verständnis einfach gelassen. :)array
ist eine Art Hinweis für$elements
das erste Argument ist einfacharray $elements
.$rows
ist ein Array von Datenbankergebnissen wie das aus der Frage.$children = buildTree(...)
Teil und die Funktion sollte ziemlich offensichtlich und einfach sein.Ich weiß, dass diese Frage alt ist, aber ich hatte ein sehr ähnliches Problem - außer mit einer sehr großen Datenmenge. Nach einigem Kampf gelang es mir, den Baum in einem Durchgang der Ergebnismenge zu erstellen - unter Verwendung von Referenzen. Dieser Code ist nicht schön, aber er funktioniert und es funktioniert ziemlich schnell. Es ist nicht rekursiv - das heißt, es gibt nur einen Durchgang über die Ergebnismenge und dann einen
array_filter
am Ende:$dbh = new PDO(CONNECT_STRING, USERNAME, PASSWORD); $dbs = $dbh->query("SELECT n_id, n_parent_id from test_table order by n_parent_id, n_id"); $elems = array(); while(($row = $dbs->fetch(PDO::FETCH_ASSOC)) !== FALSE) { $row['children'] = array(); $vn = "row" . $row['n_id']; ${$vn} = $row; if(!is_null($row['n_parent_id'])) { $vp = "parent" . $row['n_parent_id']; if(isset($data[$row['n_parent_id']])) { ${$vp} = $data[$row['n_parent_id']]; } else { ${$vp} = array('n_id' => $row['n_parent_id'], 'n_parent_id' => null, 'children' => array()); $data[$row['n_parent_id']] = &${$vp}; } ${$vp}['children'][] = &${$vn}; $data[$row['n_parent_id']] = ${$vp}; } $data[$row['n_id']] = &${$vn}; } $dbs->closeCursor(); $result = array_filter($data, function($elem) { return is_null($elem['n_parent_id']); }); print_r($result);
Bei Ausführung mit diesen Daten:
mysql> select * from test_table; +------+-------------+ | n_id | n_parent_id | +------+-------------+ | 1 | NULL | | 2 | NULL | | 3 | 1 | | 4 | 1 | | 5 | 2 | | 6 | 2 | | 7 | 5 | | 8 | 5 | +------+-------------+
Der letzte
print_r
erzeugt diese Ausgabe:Array ( [1] => Array ( [n_id] => 1 [n_parent_id] => [children] => Array ( [3] => Array ( [n_id] => 3 [n_parent_id] => 1 [children] => Array ( ) ) [4] => Array ( [n_id] => 4 [n_parent_id] => 1 [children] => Array ( ) ) ) ) [2] => Array ( [n_id] => 2 [n_parent_id] => [children] => Array ( [5] => Array ( [n_id] => 5 [n_parent_id] => 2 [children] => Array ( [7] => Array ( [n_id] => 7 [n_parent_id] => 5 [children] => Array ( ) ) [8] => Array ( [n_id] => 8 [n_parent_id] => 5 [children] => Array ( ) ) ) ) [6] => Array ( [n_id] => 6 [n_parent_id] => 2 [children] => Array ( ) ) ) ) )
Welches ist genau das, wonach ich gesucht habe.
quelle
Es ist möglich, PHP zu verwenden, um das MySQL-Ergebnis in ein Array zu bekommen und es dann zu verwenden.
$categoryArr = Array(); while($categoryRow = mysql_fetch_array($category_query_result)){ $categoryArr[] = array('parentid'=>$categoryRow['parent_id'], 'id'=>$categoryRow['id']); }
quelle