私はインターネットを見回しましたが、探しているものがまだ見つかりませんでした。各要素に「id」と「parent_id」を含むフラット配列があります。各要素には1つの親しかありませんが、複数の子を持つことができます。 parent_id = 0の場合、ルートレベルのアイテムと見なされます。フラット配列をツリーに入れようとしています。私が見つけた他のサンプルは、要素を親にコピーするだけですが、元のものはまだ存在します。
[〜#〜] edit [〜#〜]
開始配列の各要素は、個別のXMLファイルから読み取られます。ファイルに親がない場合、ファイル自体はparent_idの値として「0」になります。キーは実際には文字列です。
先ほどの混乱でごめんなさい。うまくいけば、これはより明確です:
/ EDIT
私の開始配列:
Array ( [_319_] => Array ( [id] => 0 [parent_id] => 0 ) [_320_] =>配列 ( [id] => _320 _ [parent_id] => 0 ) [_321_] =>配列 ( [id] => _321 _ [parent_id] => _320 _ ) [_322_] =>配列 ( [id] => _322 _ [parent_id] => _321 _ ) [_323_] =>配列 ( [id] => _323 _ [parent_id] => 0 ) [_324_] =>配列 ( [id] => _324 _ [parent_id] => _323 _ ) [_325_] =>配列 ( [id] => _325 _ [parent_id] => _320 _ ) )
ツリーが作成された後の結果の配列:
Array ( [_319_] => Array ( [id] => _319 _ [parent_id] => 0 ) [_320_] =>配列 ( [id] => _320 _ [parent_id] => 0 [children] => Array ( [_321_] => Array ( [id] => _321 _ [parent_id] => _320 _ [children] => Array ( [_322_] => Array ( [id] = > _322 _ [parent_id] => _321 _ ) ) ) [_325_] =>配列 ( [id] => _325 _ [parent_id] => _320 _ ) ) [_323_] =>配列 ( [id] => _323 _ [parent_id] => 0 [子供] =>配列 ( [_324_] =>配列 ( [id] => _324 _ [parent_id] => _323 _ ) ) )
ヘルプ/ガイダンスは大歓迎です!
私がこれまでに持っているいくつかのコード:
function buildTree(array&$ elements、$ parentId = 0){ $ branch = array(); foreach($ elements as $ element){ if($ element ['parent_id'] == $ parentId){ $ children = $ this-> buildTree($ elements、$ element ['id']) ; if($ children){ $ element ['children'] = $ children; } $ branch [] = $ element; } } return $ branch; }
unset()
を忘れてしまいました。
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;
}
ImmortalFireflyによる解決策は機能していますが、mrddedが指摘するように、子供のいない最初の親を救うことはできません。この問題を修正するために関数を編集しました:
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;
}
これは私のために働く:
$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);
私はロジックを見ることができ、結果でこれを保存します:
_Array
(
[0] => Array
(
[id] => 0
[parent_id] => 0
)
[1] => Array
(
[id] => 1
[parent_id] => 0
)
_
私見、parent_id = o、[1]は[0]の子ではありませんか?
とにかく、救助への参照:
_$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);
_
ルートとしての「マジック」番号と既存のIDの両方として0を悪用したため、id = 0ブランチで再帰が行われるようになりました。 _$tree[$item['parent_id']]['children'][] = &$tree[$item['id']];
_の前にif($item['parent_id']!=$item['id'])
を追加すると、それを防ぐことができますが、きれいではありません。
この関数(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>';
これは古い質問ですが、答えをここに投稿します。
/* 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
はPHP 5.5ですが、簡単に作成できます。
元のデータ構造に要素の親が存在しない場合を除き、SteveEdsonのコードは正常に機能します。これに対する私の修正は次のとおりです(ただし、要素から "parent_id"が削除されます。これは許容される場合と許容されない場合があります)。
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;
}
いくつかの問題を解決するはずなので、MySQLで階層データを保存およびロードすることを検討します。最初の配列はデータベースから直接取得したデータを表すと仮定していますか?
隣接モデルを使用してデータを階層構造に整理しようとしているようです。ネスティングを使用してこれを達成する他の方法もあります。このデータをデータベースから取得していない場合、これはそれほど有用ではない可能性があります。
このリンクはあなたを助けるはずです: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
最上位の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);
}
}
}
きれいで、短く、バラストがありません。ツリーへの配列の配列:
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));
これが私のソリューションです。他のソリューションをコピーして最適化します。
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;
}
@ eugen-rieckと同様のソリューションを思いつき、それを共有したいと考えました。私は$branches
しかし、インデックスの私の配列。
$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];
}
}