PHP递归多维数组,同时保持深度和关键举行

PHP递归多维数组,同时保持深度和关键举行

问题描述:

我已经得到了一些包含ID的,存储在名为名称键多维数组。每个项可以具有其他的子阵列,包含其它的ID。该阵列是动态的;的深度和条目是未知的。下面是一个例子:

I've got a multidimensional array containing some id's, stored in keys called 'name'. Each entry can have other sub-arrays, containing other id's. The array is dynamic; the depth and entries are unknown. Here is an example:

Array
(
    [0] => Array
        (
            [name] => test1
            [subs] => Array
                (
                    [0] => Array
                        (
                            [name] => test2
                        )

                    [1] => Array
                        (
                            [name] => test3
                            [subs] => Array
                                   (
                                       [name] => test4
                                   )
                        )

                )

        )

    [1] => Array
        (
            [name] => test5
        )
)

现在我想这个多维数组转换为平阵列,同时保持深度举行。新数组的范围是某种形式的内容,其中关键的再presents一个章节和一个ID值表。例如,TEST4应该是1.2.1章,测试2应该是1.1和'TEST5'应该是第2章中每个级别更深意味着条目是父级别的子项。因此,我要存储每个previous深度'level,而循环数组。到目前为止,我还没有找到一个方法来做到这一点。

Now I want to convert this multidimensional array to a 'flat' array, while keeping hold of the depth. The scope of the new array is some kind of table of contents, where the key represents a chapter and the value an id. For example, 'test4' should be chapter 1.2.1, 'test2' should be 1.1 and 'test5' should be chapter 2. Each level deeper means the entry is a child of the parent level. Therefore I have to store every previous depth-'level' while looping the array. So far I haven't found a way to do this.

问更新:

我已经得到了第一部分的工作。现在我想新的章节添加到数组,并有现有条目的章节编号自我更新。该阵列现在看起来是这样的:

I've got the first part working. Now I want to add new chapters to the array, and have the chapter numbers of the existing entries update themselves. The array now looks like this:

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

So now I would like to add chapter 'test6' as first-child of 1.2, which means the current 1.2.1 would become 1.2.2 and the new child will be 1.2.1 instead.

code:

// 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。

These two (plus one supporting) functions allow you add and remove chapters from the input array by chapter reference. Then, you can recalculate the TOC from the new structure.

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;
}

以证明他们是如何工作的最好方法是用一个例子。假设我们开始与阵列结构之上,它是在一个名为变量 $结构举行。正如我们所知,我们的结果TOC数组是这样的:

The best way to demonstrate how they work is with an example. Say we start with the array structure above, which is held in a variable called $structure. As we know, our resulting TOC array looks like this:

Array
(
    [1] => test1
    [1.1] => test2
    [1.2] => test3
    [1.2.1] => test4
    [2] => test5
)

现在,我们决定要删除章 1.2 和它所有的子章 - 我们可以做到这一点:

Now, we decide we want to remove chapter 1.2 and all it's sub-chapters - we can do this:

// 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 测试2 将被重新索引到 1.2 - 我们将在上面的例子中为这一个结果来工作:

Now lets say we want to add a chapter called test6 as chapter 1.1, and test2 will be re-indexed to 1.2 - we'll be working with the result of the above example for this one:

// 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
  )
*/

OK,似乎相当简单。但是,如果我们想要什么样的移动的一个章子,所以它在树的*别?让我们回到我们原来的 $结构的版本来证明这一点 - 我们将继续前进章 1.2 ,以便它现在章 3

OK, seems fairly simple. But what if we wanted to move a sub-chapter, so it was at the top level of the tree? Let's go back to our original version of $structure to demonstrate this - we'll move chapter 1.2, so that it is now chapter 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
  )
*/

我希望我已经解释的不够好那里。

Hopefully I've explained it well enough there.

chapter_exists()返回一个布尔值。相当自我解释为它意味着什么,如果感觉。传 $结构数组作为第一个参数,并要检查作为第二章ID。此功能是必需的,因为它是用来由其它两个内部

chapter_exists() returns a boolean. Fairly self explanatory as to what it means, if feel. Pass the $structure array as the first parameter, and the chapter ID you want to check as the second. This function is required, as it is used by the other two internally.

add_chapter()返回一个布尔值,这样你就可以测试操作是否成功。如果本章的父不存在它会失败 - 如果你尝试添加例如 1.2.1 1.2 尚未定义,它不会工作。如果添加一个已经存在的章节,在该级别的所有章节编号将由1上移。

add_chapter() returns a boolean, so you can test whether the operation was successful. It will fail if the parent of the chapter doesn't exist - for example, if you try to add 1.2.1 when 1.2 hasn't been defined, it won't work. If you add a chapter that already exists, all the chapter numbers at that level will be shifted up by 1.

remove_chapter()将返回成功被删除的项目(即数组)或布尔 FALSE 上失败 - 如果你尝试并删除不存在的章节将会失败

remove_chapter() will return the item that was removed on success (i.e. an array) or boolean FALSE on failure - it will fail if you try and remove a chapter that doesn't exist.

注:我不得不大量使用的eval()对于这一点,以适应任意级别的深度。我不想使用它,但我想不出任何其他方式 - 如果任何人阅读此大约有(不涉及一些噩梦般的循环结构preferably)的替代方法什么好​​主意,请让我知道..

NB: I had to make heavy use of eval() for this, in order to accommodate for arbitrary level depth. I hate to use it, but I couldn't think of any other way - if anyone reading this has any bright ideas about alternative approaches (preferably that don't involve some nightmarish looping structure), please let me know...