我有一个包含一些id的多维数组,存储在名为'name'的键中。每个条目都可以包含其他子数组,包含其他ID。阵列是动态的;深度和条目未知。这是一个例子:
Array
(
[0] => Array
(
[name] => test1
[subs] => Array
(
[0] => Array
(
[name] => test2
)
[1] => Array
(
[name] => test3
[subs] => Array
(
[name] => test4
)
)
)
)
[1] => Array
(
[name] => test5
)
)
现在我想将这个多维数组转换为'flat'数组,同时保持深度。新数组的范围是某种目录,其中键表示章节,值表示id。例如,'test4'应该是1.2.1章,'test2'应该是1.1而'test5'应该是第2章。每个级别更深意味着该条目是父级别的子级。因此,我必须在循环数组时存储每个先前的深度 - 'level'。到目前为止,我还没有找到办法做到这一点。
问题更新:
我的第一部分工作。现在我想在数组中添加新的章节,并让现有条目的章节编号自行更新。该阵列现在看起来像这样:
Array
(
[1] => test1
[1.1] => test2
[1.2] => test3
[1.2.1] => test4
[2] => test5
)
所以现在我想添加章节'test6'作为1.2的第一个孩子,这意味着当前1.2.1将变为1.2.2而新孩子将变为1.2.1。
答案 0 :(得分:3)
代码:
// Mmmm... functiony goodness
function array_to_toc ($in, &$out, $level = '') {
if (!$level) $out = array(); // Make sure $out is an empty array at the beginning
foreach ($in as $key => $item) { // Loop items
$thisLevel = ($level) ? "$level.".($key + 1) : ($key + 1); // Get this level as string
$out[$thisLevel] = $item['name']; // Add this item to $out
if (isset($item['subs']) && is_array($item['subs']) && count($item['subs'])) array_to_toc($item['subs'],$out,$thisLevel); // Recurse children of this item
}
}
// Here is your test data (slightly modified - I think you stated it wrong in the question)
$array = array (
0 => array (
'name' => 'test1',
'subs' => array (
0 => array (
'name' => 'test2'
),
1 => array (
'name' => 'test3',
'subs' => array (
0 => array (
'name' => 'test4'
)
)
)
)
),
1 => array (
'name' => 'test5'
)
);
// $result is passed by reference and will hold the output after the function has run
$result = array();
array_to_toc($array, $result);
print_r($result);
输出:
Array
(
[1] => test1
[1.1] => test2
[1.2] => test3
[1.2.1] => test4
[2] => test5
)
修改强>
这两个(加上一个支持)函数允许您通过章节参考添加和删除输入数组中的章节。然后,您可以从新结构重新计算TOC。
function chapter_exists ($array, $chapterId) {
$chapterParts = explode('.',$chapterId);
foreach ($chapterParts as &$chapter) $chapter--;
$lastId = array_pop($chapterParts);
return eval('return isset($array['.implode("]['subs'][",$chapterParts).((count($chapterParts)) ? "]['subs'][" : '')."$lastId]);");
}
function add_chapter (&$array, $chapterId, $item) {
$chapterParts = explode('.',$chapterId);
foreach ($chapterParts as &$chapter) $chapter--; // Decrement all the values
$lastId = array_pop($chapterParts);
if (count($chapterParts) && !chapter_exists($array, implode('.',$chapterParts))) return FALSE; // Return FALSE if the level above the chapter we are adding doesn't exist
if (chapter_exists($array, $chapterId)) { // See if the chapter reference already exists
eval('array_splice($array'.((count($chapterParts)) ? '['.implode("]['subs'][",$chapterParts)."]['subs']" : '').",$lastId,0,array(\$item));"); // Insert an item
} else {
eval('$array['.implode("]['subs'][",$chapterParts).((count($chapterParts)) ? "]['subs'][" : '')."$lastId] = \$item;"); // Insert an item
}
return TRUE;
}
function remove_chapter (&$array, $chapterId) {
$chapterParts = explode('.',$chapterId);
foreach ($chapterParts as &$chapter) $chapter--; // Decrement all the values
$lastId = array_pop($chapterParts);
return (chapter_exists($array, $chapterId)) ? eval('$removed = array_splice($array'.((count($chapterParts)) ? '['.implode("]['subs'][",$chapterParts)."]['subs']" : '').",$lastId,1); return array_shift(\$removed);") : FALSE;
}
演示它们如何工作的最佳方式是一个例子。假设我们从上面的数组结构开始,该结构保存在名为$structure
的变量中。众所周知,我们生成的TOC数组如下所示:
Array
(
[1] => test1
[1.1] => test2
[1.2] => test3
[1.2.1] => test4
[2] => test5
)
现在,我们决定删除章节1.2
及其所有子章节 - 我们可以这样做:
// Remove the chapter from $structure
remove_chapter($structure, '1.2');
// recalculate the TOC
array_to_toc($structure, $result2);
print_r($result2);
/*
Outputs:
Array
(
[1] => test1
[1.1] => test2
[2] => test5
)
*/
现在假设我们要添加一个名为test6
的章节作为章节1.1
,test2
将重新编入1.2
- 我们将与之合作上面这个例子的结果:
// Add the new chapter to $structure
add_chapter($structure, '1.1', array('name'=>'test6'));
// recalculate the TOC
array_to_toc($structure, $result3);
print_r($result3);
/*
Outputs:
Array
(
[1] => test1
[1.1] => test6
[1.2] => test2
[2] => test5
)
*/
好的,看起来很简单。但是,如果我们想移动一个子章节,那么它是在树的最顶层呢?让我们回到我们原始版本的$structure
来证明这一点 - 我们将移动章节1.2
,现在它已经是章3
:
/*
A quick reminder of what we are starting with:
Array
(
[1] => test1
[1.1] => test2
[1.2] => test3
[1.2.1] => test4
[2] => test5
)
*/
// Remove the chapter from $structure - this time, we'll catch the items we remove in a variable
$removed = remove_chapter($structure, '1.2');
// Add it again, only this time as chapter 3
add_chapter($structure, '3', $removed);
// recalculate the TOC
array_to_toc($structure, $result4);
print_r($result4);
/*
Outputs:
Array
(
[1] => test1
[1.1] => test2
[2] => test5
[3] => test3
[3.1] => test4
)
*/
希望我在那里解释得很好。
chapter_exists()
返回一个布尔值。如果感觉如此,它的含义是相当自我解释的。将$structure
数组作为第一个参数传递,将要检查的章节ID作为第二个参数传递。此功能是必需的,因为其他两个内部使用它。
add_chapter()
返回一个布尔值,因此您可以测试操作是否成功。如果章节的父级不存在,它将失败 - 例如,如果在未定义1.2.1
时尝试添加1.2
,则无效。如果添加已存在的章节,则该级别的所有章节编号将向上移动1。
remove_chapter()
将返回成功时删除的项(即数组)或失败时的布尔FALSE
- 如果您尝试删除不存在的章节,它将失败。
注意:为了适应任意级别的深度,我必须大量使用eval()
。我讨厌使用它,但我想不出任何其他方式 - 如果有人读到这个有任何关于替代方法的明智想法(最好不涉及一些噩梦循环结构),请告诉我......
答案 1 :(得分:0)
function toc(array $data, array $level = array()) {
$toc = array();
foreach ($data as $i => $node) {
$currentLevel = array_merge($level, array($i + 1));
$toc[] = join('.', $currentLevel) . ': ' . $node['name'];
if (!empty($node['subs'])) {
$toc = array_merge($toc, toc($node['subs'], $currentLevel));
}
}
return $toc;
}
echo join("\n", toc($array));
答案 2 :(得分:0)
function array_flat($array, $prefix = '') {
$result = array();
foreach ($array as $key => $value) {
$new_key = $prefix . (empty($prefix) ? '' : '.') . $key;
if (is_array($value)) {
$result = array_merge($result, array_flat($value, $new_key));
} else {
$result[$new_key] = $value;
}
}
return $result;
}