PHP 递归:展平树,保留元数据
PHP Recursion: Flatten Tree, Preserve Metadata
想象一下,您有一棵树代表一个您希望保留在表中但保留嵌套级别的家族。我想将下面的 post 数据放入下面的结构中。
我相信 RecursiveIterator 可能是执行此操作的方法,但我不确定我将如何操作。我有适用于大多数情况的代码,但它已经变得丑陋、臃肿。如果你愿意,我可以 post。
stdClass Object
(
[name] => Smith
[type] => Family
[children] => Array(
[1] => stdClass Object
(
[name] => Michael
[type] => Uncle
[children] => Array(
[0] => stdClass Object
(
[name] => Jared
[type] => cousin
)
)
)
[2] => stdClass Object
(
[name] => Jeff
[type] => Dad
[children] => Array(
[0] => stdClass Object
(
[name] => Jonas
[type] => self
)
[1] => stdClass Object
(
[name] => Leah
[type] => sister
[children] => Array(
[0] => stdClass Object
(
[name] => Jacob
[type] => nephew
)
)
)
)
)
)
)
持久化的记录应该是这样的:
Array
(
stdClass Object ( [name] => Smith [type] => Family [subgroup] => 0 [parent_subgroup] => )
stdClass Object ( [name] => Michael [type] => Uncle [subgroup] => 1 [parent_subgroup] => 0 )
stdClass Object ( [name] => Jared [type] => Cousin [subgroup] => 2 [parent_subgroup] => 1 )
stdClass Object ( [name] => Jeff [type] => Dad [subgroup] => 1 [parent_subgroup] => 0 )
stdClass Object ( [name] => Jonas [type] => self [subgroup] => 3 [parent_subgroup] => 1 )
stdClass Object ( [name] => Leah [type] => sister [subgroup] => 3 [parent_subgroup] => 1 )
stdClass Object ( [name] => Jacob [type] => nephew [subgroup] => 4 [parent_subgroup] => 3 )
)
P.S。不,我和我姐姐没有孩子。那只是我的类比。 ;)
RecursiveIterator
classes 可能会有点乱,我喜欢尽量保持简单。您可以使用 RecursiveIteratorIterator
遍历迭代器的值,它甚至可以为您提供当前深度(或 subgroup
在您的情况下)。
这里的挑战是父级不是数组,但我们可以在构造函数中处理它。
<?php
class FamilyIterator implements RecursiveIterator{
private $data, $counter;
public function __construct($familyTree){
$this->data = is_array($familyTree) ? $familyTree : [$familyTree];
}
public function current(){
$row = $this->data[$this->counter];
return (object)[
'name' => $row->name,
'type' => $row->type
];
}
public function key(){
return $this->counter;
}
public function next(){
$this->counter++;
}
public function rewind(){
$this->counter = 0;
}
public function valid(){
return $this->counter < count($this->data);
}
public function hasChildren(){
$row = $this->data[$this->counter];
return isset($row->children);
}
public function getChildren(){
$row = $this->data[$this->counter];
return new self($row->children);
}
}
然后你可以像这样使用这个class:
$loop = new RecursiveIteratorIterator(
new FamilyIterator($dataObj),
RecursiveIteratorIterator::SELF_FIRST
);
当您 foreach
超过 $loop
时,它会在需要时自动调用 getChildren
方法,因此在 foreach
中您将拥有每一行。你甚至可以问 RecursiveIteratorIterator
深度。
$newData = [];
foreach($loop as $row){
$row->subgroup = $loop->getDepth();
$newData[] = $row;
}
这可能不完全您想要的,但希望它能为您指明正确的方向。 RecursiveIterator
不需要太复杂。
想象一下,您有一棵树代表一个您希望保留在表中但保留嵌套级别的家族。我想将下面的 post 数据放入下面的结构中。
我相信 RecursiveIterator 可能是执行此操作的方法,但我不确定我将如何操作。我有适用于大多数情况的代码,但它已经变得丑陋、臃肿。如果你愿意,我可以 post。
stdClass Object
(
[name] => Smith
[type] => Family
[children] => Array(
[1] => stdClass Object
(
[name] => Michael
[type] => Uncle
[children] => Array(
[0] => stdClass Object
(
[name] => Jared
[type] => cousin
)
)
)
[2] => stdClass Object
(
[name] => Jeff
[type] => Dad
[children] => Array(
[0] => stdClass Object
(
[name] => Jonas
[type] => self
)
[1] => stdClass Object
(
[name] => Leah
[type] => sister
[children] => Array(
[0] => stdClass Object
(
[name] => Jacob
[type] => nephew
)
)
)
)
)
)
)
持久化的记录应该是这样的:
Array
(
stdClass Object ( [name] => Smith [type] => Family [subgroup] => 0 [parent_subgroup] => )
stdClass Object ( [name] => Michael [type] => Uncle [subgroup] => 1 [parent_subgroup] => 0 )
stdClass Object ( [name] => Jared [type] => Cousin [subgroup] => 2 [parent_subgroup] => 1 )
stdClass Object ( [name] => Jeff [type] => Dad [subgroup] => 1 [parent_subgroup] => 0 )
stdClass Object ( [name] => Jonas [type] => self [subgroup] => 3 [parent_subgroup] => 1 )
stdClass Object ( [name] => Leah [type] => sister [subgroup] => 3 [parent_subgroup] => 1 )
stdClass Object ( [name] => Jacob [type] => nephew [subgroup] => 4 [parent_subgroup] => 3 )
)
P.S。不,我和我姐姐没有孩子。那只是我的类比。 ;)
RecursiveIterator
classes 可能会有点乱,我喜欢尽量保持简单。您可以使用 RecursiveIteratorIterator
遍历迭代器的值,它甚至可以为您提供当前深度(或 subgroup
在您的情况下)。
这里的挑战是父级不是数组,但我们可以在构造函数中处理它。
<?php
class FamilyIterator implements RecursiveIterator{
private $data, $counter;
public function __construct($familyTree){
$this->data = is_array($familyTree) ? $familyTree : [$familyTree];
}
public function current(){
$row = $this->data[$this->counter];
return (object)[
'name' => $row->name,
'type' => $row->type
];
}
public function key(){
return $this->counter;
}
public function next(){
$this->counter++;
}
public function rewind(){
$this->counter = 0;
}
public function valid(){
return $this->counter < count($this->data);
}
public function hasChildren(){
$row = $this->data[$this->counter];
return isset($row->children);
}
public function getChildren(){
$row = $this->data[$this->counter];
return new self($row->children);
}
}
然后你可以像这样使用这个class:
$loop = new RecursiveIteratorIterator(
new FamilyIterator($dataObj),
RecursiveIteratorIterator::SELF_FIRST
);
当您 foreach
超过 $loop
时,它会在需要时自动调用 getChildren
方法,因此在 foreach
中您将拥有每一行。你甚至可以问 RecursiveIteratorIterator
深度。
$newData = [];
foreach($loop as $row){
$row->subgroup = $loop->getDepth();
$newData[] = $row;
}
这可能不完全您想要的,但希望它能为您指明正确的方向。 RecursiveIterator
不需要太复杂。