PHP从具有关系数据的数组创建多维数组[重复]
Posted
技术标签:
【中文标题】PHP从具有关系数据的数组创建多维数组[重复]【英文标题】:PHP Create a Multidimensional Array from an array with relational data [duplicate] 【发布时间】:2012-06-29 16:17:13 【问题描述】:可能重复:Converting an array from one to multi-dimensional based on parent ID values
我正在使用 php。
我有以下包含关系数据(父子关系)的数组。
Array
(
[5273] => Array
(
[id] => 5273
[name] => John Doe
[parent] =>
)
[6032] => Array
(
[id] => 6032
[name] => Sally Smith
[parent] => 5273
)
[6034] => Array
(
[id] => 6034
[name] => Mike Jones
[parent] => 6032
)
[6035] => Array
(
[id] => 6035
[name] => Jason Williams
[parent] => 6034
)
[6036] => Array
(
[id] => 6036
[name] => Sara Johnson
[parent] => 5273
)
[6037] => Array
(
[id] => 6037
[name] => Dave Wilson
[parent] => 5273
)
[6038] => Array
(
[id] => 6038
[name] => Amy Martin
[parent] => 6037
)
)
我需要它是这种 JSON 格式:
"id":"5273",
"name":"John Doe",
"data":
,
"children":[
"id":" Sally Smith",
"name":"6032",
"data":
,
"children":[
"id":"6034",
"name":"Mike Jones",
"data":
,
"children":[
"id":"6035",
"name":"Jason Williams",
"data":
,
"children":[
"id":"node46",
"name":"4.6",
"data":
,
"children":[
]
]
]
,
"id":"6036",
"name":"Sara Johnson",
"data":
,
"children":[
]
,
"id":"6037",
"name":"Dave Wilson",
"data":
,
"children":[
"id":"6038",
"name":"Amy Martin",
"data":
,
"children":[
]
]
]
]
我知道我需要创建一个多维数组并通过 json_encode() 运行它。我还认为用于执行此操作的这种方法需要递归,因为现实世界的数据可能具有未知数量的级别。
我很乐意展示我的一些方法,但它们没有奏效。
谁能帮帮我?
我被要求分享我的工作。这是我尝试过的,但我没有得到那么接近我不知道它有多大帮助。
我制作了一个仅包含关系的数组。
foreach($array as $k => $v)
$relationships[$v['id']] = $v['parent'];
我认为(基于另一篇 SO 帖子)使用此关系数据创建了一个新的多维数组。如果我让它工作,我将努力添加正确的“儿童”标签等。
$childrenTable = array();
$data = array();
foreach ($relationships as $n => $p)
//parent was not seen before, put on root
if (!array_key_exists($p, $childrenTable))
$childrenTable[$p] = array();
$data[$p] = &$childrenTable[$p];
//child was not seen before
if (!array_key_exists($n, $childrenTable))
$childrenTable[$n] = array();
//root node has a parent after all, relocate
if (array_key_exists($n, $data))
unset($data[$n]);
$childrenTable[$p][$n] = &$childrenTable[$n];
unset($childrenTable);
print_r($data);
【问题讨论】:
您发布的初始格式是一个多维数组。这不应该在 json 编码中工作吗? Ben Roux,是的,这是一个多维数组,但生成该 JSON 的格式不正确。 你试过什么?发布你的代码你是如何准备数组的。 Sanjay,我在我的问题中添加了一些我的工作。我无法在 cmets 中获得正确的格式。我也尝试过do-while,但也失败了。 Yoshi,我回过头来记下所有以前的答案都是某些解决方案。我希望这有帮助。我以后会更好地跟上这一点。 【参考方案1】:<?php
header('Content-Type: application/json; charset="utf-8"');
/**
* Helper function
*
* @param array $d flat data, implementing a id/parent id (adjacency list) structure
* @param mixed $r root id, node to return
* @param string $pk parent id index
* @param string $k id index
* @param string $c children index
* @return array
*/
function makeRecursive($d, $r = 0, $pk = 'parent', $k = 'id', $c = 'children')
$m = array();
foreach ($d as $e)
isset($m[$e[$pk]]) ?: $m[$e[$pk]] = array();
isset($m[$e[$k]]) ?: $m[$e[$k]] = array();
$m[$e[$pk]][] = array_merge($e, array($c => &$m[$e[$k]]));
return $m[$r][0]; // remove [0] if there could be more than one root nodes
echo json_encode(makeRecursive(array(
array('id' => 5273, 'parent' => 0, 'name' => 'John Doe'),
array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),
array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),
array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),
array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),
array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),
array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),
)));
演示:https://3v4l.org/s2PNC
【讨论】:
耀西,谢谢。我针对测试运行了您的代码,并且效果很好。但是,当我实施一些现实世界的数据时,可能是 300-400 人。我得到一个 PHP 用尽 128mb 的内存错误。我知道 300-400 条记录比我提供的示例要多,但我认为它不会被视为大型数据集。有任何想法吗?这使用这么多内存有意义吗? @maestrojed 我的第一个版本出现错误(可能是内存泄漏的原因),请查看更新。 这很有效,而且超出了我的预期。谢谢您的帮助。我期待着分析它并学习一些东西! @Yoshi 经过几次检查后,我发现如果您有多个***父母,您应该return $m[$r]
。无论如何,感谢您的解决方案。
@Yoshi 明白了,谢谢兄弟,你的意思是这个 (ref - &) 将变量本身放在子部分中,而不是它的值的副本,它在最终输出中获得它的值【参考方案2】:
好的,这就是它的工作原理,实际上您在开始时并没有走得太远,但您实际寻找的是参考资料。这是一个通用程序:
由于父节点和子节点的 ID 之间存在关系,因此您首先需要根据 ID 对数据进行索引。我在这里用一个数组($rows
)来模拟你的数据访问,如果你从数据库中读取,它会是相似的。通过此索引,您还可以添加其他属性,例如空数据:
// create an index on id
$index = array();
foreach($rows as $row)
$row['data'] = (object) array();
$index[$row['id']] = $row;
所以现在所有条目都根据它们的 ID 编制索引。这是第一步。
第二步同样直截了当。因为我们现在可以根据 $index
中的 ID 访问每个节点,所以我们可以将子节点分配给它们的父节点。
有一个“虚拟”节点,即 ID 为 0 的节点。它不存在于任何行中,但是,如果我们也可以向其添加子节点,我们可以将此子节点集合用作存储对于所有根节点,在您的情况下,只有一个根节点。
当然,对于 ID 0
,我们不应该处理父级 - 因为它不存在。
那么让我们这样做吧。我们在这里使用引用,因为否则同一个节点不能既是父节点又是子节点:
// build the tree
foreach($index as $id => &$row)
if ($id === 0) continue;
$parent = $row['parent'];
$index[$parent]['children'][] = &$row;
unset($row);
因为我们使用引用,所以最后一行注意在循环之后取消设置存储在$row
中的引用。
现在所有孩子都已分配给他们的父母。可能已经是这样了,但是不要忘记最后一步,应该访问输出的实际节点。
为简洁起见,只需将根节点分配给$index
本身。如果我们还记得,我们想要的唯一根节点是子数组中 ID 为 0
的节点中的第一个:
// obtain root node
$index = $index[0]['children'][0];
就是这样。我们现在可以直接使用它来生成 JSON:
// output json
header('Content-Type: application/json');
echo json_encode($index);
最后一目了然整个代码:
<?php
/**
* @link http://***.com/questions/11239652/php-create-a-multidimensional-array-from-an-array-with-relational-data
*/
$rows = array(
array('id' => 5273, 'parent' => 0, 'name' => 'John Doe'),
array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'),
array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'),
array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'),
array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'),
array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'),
array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'),
);
// create an index on id
$index = array();
foreach($rows as $row)
$row['data'] = (object) [];
$index[$row['id']] = $row;
// build the tree
foreach($index as $id => &$row)
if ($id === 0) continue;
$parent = $row['parent'];
$index[$parent]['children'][] = &$row;
unset($row);
// obtain root node
$index = $index[0]['children'][0];
// output json
header('Content-Type: application/json');
echo json_encode($index, JSON_PRETTY_PRINT);
这将创建以下 json(此处使用 PHP 5.4s'JSON_PRETTY_PRINT
):
"id": 5273,
"parent": 0,
"name": "John Doe",
"data":
,
"children": [
"id": 6032,
"parent": 5273,
"name": "Sally Smith",
"data":
,
"children": [
"id": 6034,
"parent": 6032,
"name": "Mike Jones",
"data":
,
"children": [
"id": 6035,
"parent": 6034,
"name": "Jason Williams",
"data":
]
]
,
"id": 6036,
"parent": 5273,
"name": "Sara Johnson",
"data":
,
"id": 6037,
"parent": 5273,
"name": "Dave Wilson",
"data":
,
"children": [
"id": 6038,
"parent": 6037,
"name": "Amy Martin",
"data":
]
]
【讨论】:
你能解释一下 unset($row);正在做 @LovepreetSinghBatth:它是“因为我们使用引用,所以最后一行注意在循环后取消设置存储在 $row 中的引用。”在它所在的示例下方。【参考方案3】:以下代码将完成这项工作..您可能需要根据需要进行一些调整。
$data = array(
'5273' => array( 'id' =>5273, 'name'=> 'John Doe', 'parent'=>''),
'6032' => array( 'id' =>6032, 'name'=> 'Sally Smith', 'parent'=>'5273'),
'6034' => array( 'id' =>6034, 'name'=> 'Mike Jones ', 'parent'=>'6032'),
'6035' => array( 'id' =>6035, 'name'=> 'Jason Williams', 'parent'=>'6034')
);
$fdata = array();
function ConvertToMulti($data)
global $fdata;
foreach($data as $k => $v)
if(empty($v['parent']))
unset($v['parent']);
$v['data'] = array();
$v['children'] = array();
$fdata[] = $v;
else
findParentAndInsert($v, $fdata);
function findParentAndInsert($idata, &$ldata)
foreach ($ldata as $k=>$v)
if($ldata[$k]['id'] == $idata['parent'])
unset($idata['parent']);
$idata['data'] = array();
$idata['children'] = array();
$ldata[$k]['children'][] = $idata;
return;
else if(!empty($v['children']))
findParentAndInsert($idata, $ldata[$k]['children']);
print_r($data);
ConvertToMulti($data);
echo "AFTER\n";
print_r($fdata);
http://codepad.viper-7.com/Q5Buaz
【讨论】:
我会在早上继续尝试这个。在第一次实施时,它似乎有问题。我还不确定是什么,并将尝试详细评论。当我实现它时,我没有收到错误,结构似乎正确,但缺少很多数据。 请注意几件事,首先,用你的填充 $data 数组。它没有您在问题中使用的所有值。其次,您可以将 $fdata 设为 ConvertToMulti 函数的本地变量。使其全局化可能会导致您的实施出现问题。祝您实施顺利以上是关于PHP从具有关系数据的数组创建多维数组[重复]的主要内容,如果未能解决你的问题,请参考以下文章