2

having this array of file paths

paths: Array
(
   [0] => folder1/content/file1.php
   [1] => folder1/content/file2.php
   [2] => folder1/edit/file1.php
   [3] => folder1/edit/file2.php
   [4] => folder1/pagination/file1.php
   [5] => folder1/pagination/file2.php
   [6] => folder1/toolbar/file1.php
   [7] => folder1/toolbar/file2.php
   [8] => folder2/cms/html/file1.php
   [9] => folder2/cms/html/file2.php
)

how can I parse it memory-efficiently into an HTML-grouped-list-element? The final grouping must look like:

final: Array
(
   [folder1] => Array
   (
     [content] => Array
     (
        [0] => file1.php
        [1] => file2.php
     )
     [edit] => Array
     (
        [0] => file1.php
        [1] => file2.php
     )
     [pagination] => Array
     (
        [0] => file1.php
        [1] => file2.php
     )
     [toolbar] => Array
     (
        [0] => file1.php
        [1] => file2.php
     )
   )
   [folder2] => Array
   (
     [cms] => Array
     (
        [html] => Array
        (
           [0] => file1.php
           [1] => file2.php
        )
     )
   )
)

I noticed the paths are of variable depths and stuck with this problem. The parsing routine must not be fixed to a specified recursion level. It rather iterates over a file path until the file name is left and adds this file to the array. I tried several approaches - the foreach loop, array_walk() and array_reduce(), but cannot achieve what I want.

EDIT

Here is my final try to satifiy those in doubt about my effort to find a solution myself before asking:

$groups = [];

foreach ($paths as $path)
{
    $pieces = explode(DIRECTORY_SEPARATOR, $path);

    if (!array_key_exists(($first = array_shift($pieces)), $groups))
    {
        $groups[$first] = [];

        // Mhm ... how to recoursively nest further 
        // arrays for every path level left?
    }
}
user1014412
  • 359
  • 1
  • 2
  • 15
  • The before and after data is very helpful to us, but we need to see your code too. What have you tried so far? – Surreal Dreams Aug 28 '14 at 18:34
  • I don't know what you mean with before and after data. My tryings look exactly the same as the suggestion of [user3659034](http://stackoverflow.com/a/25555801/1014412) foreach loop. The only difference it that i replaced the foreach loop with array_walk() and array_reduce() to prevent the memory-expensive duplications of the arrays being looped through via foreach. – user1014412 Aug 28 '14 at 18:50
  • You supplied data that you receive **before** processing, and what you want for a result **after** processing. You should post your code as it will have differences from any suggestions below. It proves you tried something, and answers below may be deleted in the future, leaving your question incomplete. Besides, you may be closer to a solution than you think. – Surreal Dreams Aug 28 '14 at 18:53
  • The code to generate the files list is irrelevant for this issue. I read the contents of a folder to get a list of the files in there and want to create a grouped dropdown list out of it. Thats it. The data provided above is what i have and what the issue is based on. Why must i prove i tried something? I know i tried a couple ways and with every new try the previous implementation was overridden. So the final try doesn't look very different than user3659034's suggestion below. – user1014412 Aug 28 '14 at 18:55
  • I'm not concerned with how you get the data you want to operate on - you're correct that it's irrelevant. I want to see how you tried to get your results. You'll notice that user3659034 deleted his answer below, which is why your attempt is important. I'm not trying to give you a hard time - I'm actually trying to ensure that you get help and that this question and answer are useful resources in the future. – Surreal Dreams Aug 28 '14 at 19:33
  • I am also always motivated to provide quality questions, `on point` information and quality answers since i expect to find myself to come back in the future and find this solution again. But sometimes it is my impression that proving one's effort in finding a solution oneself before asking just not to get down-voted is more important than working the problem itself. I edited my initial post and provided what i got. – user1014412 Aug 28 '14 at 19:39

2 Answers2

0

Finally i found the solution in the combination of the solution from a similar problem and array_merge_recursive(). Thanks to all responders for their effort.

Community
  • 1
  • 1
user1014412
  • 359
  • 1
  • 2
  • 15
0

There are several techniques that will do the job. I'll provide three methods that will use the following input and provide the same output (input & output at bottom of my post).

Code: #1 - Stacking Method without Modifying By Reference Demo Link

$result = [];
foreach ($paths as $path) {
    $entries = array_reverse(explode("/", $path));      // use DIRECTORY_SEPARATOR for greater utility
    foreach ($entries as $i=>$entry) {
        if (!$i) {                                      // if index value is zero
            $item=[$entry];                             // store filename as indexed element
        } else {
            $item[$entry][key($item)] = array_shift($item);  // store previous element in new level using new entry and previous key; while destroying previous element
        }
    }
    $result = array_merge_recursive($result, $item);  // merge new associative array with existing results
}
var_export($result);

Code #2 - Recursive Method Demo Link

function pathToNestedArray($path, $separator = "/") {       // use DIRECTORY_SEPARATOR for greater utility
    $halves = explode($separator, $path, 2);                // maximum explosion is 2 elements
    if (!isset($halves[1])) return [$path];                 // no folder to nest into, append as indexed element (Done)
    return [$halves[0] => pathToNestedArray($halves[1])];   // apply level's key value and recurse
}

$result = [];
foreach ($paths as $path) {
    $result = array_merge_recursive($result, pathToNestedArray($path));  // merge new associative array with existing results
}
var_export($result);

Code #3: - Stacking Method with Modifying By Reference Demo Link

$result = [];
foreach ($paths as $path) {
    $temp = &$result;                  // make $result modifiable by reference
    $entries = explode("/", $path);    // use DIRECTORY_SEPARATOR for greater utility 
    $file = array_pop($entries);       // remove the file from the array
    foreach ($entries as $folder) {
        $temp = &$temp[$folder];       // store folder as key
    }
    $temp[] = $file;                   // story indexed element (file) to temp reference
    unset($temp);                      // destroy the reference
}
var_export($result);

Input:

$paths = [
    "fileZ.php",
    "folder1/content/file1.php",
    "folder1/content/file2.php",
    "folder1/edit/file1.php",
    "folder1/edit/file2.php",
    "folder1/pagination/file1.php",
    "folder1/pagination/file2.php",
    "folder1/toolbar/file1.php",
    "folder1/toolbar/file2.php",
    "folder2/cms/html/file1.php",
    "folder2/cms/html/file2.php"
];

Output:

array (
  0 => 'fileZ.php',
  'folder1' => 
  array (
    'content' => 
    array (
      0 => 'file1.php',
      1 => 'file2.php',
    ),
    'edit' => 
    array (
      0 => 'file1.php',
      1 => 'file2.php',
    ),
    'pagination' => 
    array (
      0 => 'file1.php',
      1 => 'file2.php',
    ),
    'toolbar' => 
    array (
      0 => 'file1.php',
      1 => 'file2.php',
    ),
  ),
  'folder2' => 
  array (
    'cms' => 
    array (
      'html' => 
      array (
        0 => 'file1.php',
        1 => 'file2.php',
      ),
    ),
  ),
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • @user1014412 I've provided a comprehensive set of solutions for you (and so that future researchers don't need to chase links). Unless there is something unsuitable about my answer, please award the green tick so that your question is deemed resolved. – mickmackusa Apr 16 '18 at 23:14