0

So I've got a list of paths, such as:

path/to/directory/file1
path/directory/file2
path2/dir/file3
path2/dir/file4

And I'd like to convert them into a multidimensional array like this:

array(
  path => array(
    to => array(
      directory => array(
        file1 => someValue
      ),
    ),
    directory => array(
      file2 => someValue
    ),
  ),
  path2 => array(
    dir => array(
      file3 => someValue,
      file4 => someValue
    )
  )
)

My first thought was to explode() the paths into segments and set up the array using a foreach loop, something like this:

$arr = array();
foreach ( $path as $p ) {
    $segments = explode('/', $p);
    $str = '';
    foreach ( $segments as $s ) {
        $str .= "[$s]";
    }
    $arr{$str} = $someValue;
}

But this doesn't work, and since the number of segments varies, I've kinda got stumped. Is there away to do this?

Chris
  • 4,277
  • 7
  • 40
  • 55
  • See: http://stackoverflow.com/questions/952263/deep-recursive-array-of-directory-structure-in-php or http://stackoverflow.com/questions/952263/deep-recursive-array-of-directory-structure-in-php – Mike Jul 04 '15 at 19:50

4 Answers4

1

If somevalue can be an empty array:

<?php
$result = array();

$input = [
    'path/to/directory/file1',
    'path/directory/file2',
    'path2/dir/file3',
    'path2/dir/file4',
];

foreach( $input as $e ) {
    nest( $result, explode('/', $e));
}

var_export($result);


function nest(array &$target, array $parts) {
    if ( empty($parts) ) {
        return;
    }
    else {
        $e = array_shift($parts);
        if ( !isset($target[$e]) ) {
            $target[$e] = [];
        }
        nest($target[$e], $parts);
    }
}
VolkerK
  • 95,432
  • 20
  • 163
  • 226
0

Here is the solution and a easy way
Just Reverse the whole exploded array and start creating array within a Array

$path[1] = "path/to/directory/file1";
$path[2] = "path/directory/file2";
$path[3] = "path2/dir/file3";
$path[4] = "path2/dir/file4";
$arr = array();
$b = array();
$k = 0;
foreach($path as $p) {

$c = 0;
$segments = explode('/', $p);
$reversed = array_reverse($segments);
foreach($reversed as $s) {
if ($c == 0) {
  $g[$k] = array($s => "somevalue");

} else {

  $g[$k] = array($s => $g[$k]);
}

$c++;
}
$k++;

}
var_dump($g);
  • Thanks! But it's not quite what I was looking for. It places each sub-array in an integer-indexed array and it doesn't group files from the same path together. – Chris Jul 04 '15 at 21:13
  • yes i agree it is adding sub-array but if you print_r($g) you will find all file path being together – allvideolectures Jul 04 '15 at 21:18
0

Thanks so much VolkerK! Your answer didn't quite answer my question but it got me on the right track. Here's the version I ended up using to get it to work:

$result = array();

$input = [
    'path/to/directory/file1' => 'someValue',
    'path/directory/file2' => 'someValue',
    'path2/dir/file3' => 'someValue',
    'path2/dir/file4' => 'someValue',
];

foreach( $input as $e=>$val ) {
    nest( $result, explode('/', $e), $val);
}

var_export($result);

function nest(array &$target, array $parts, $leafValue) {

    $e = array_shift($parts);

    if ( empty($parts) ) {
        $target[$e] = $leafValue;
        return;
    }

    if ( !isset($target[$e]) ) {
        $target[$e] = [];
    }

    nest($target[$e], $parts, $leafValue);
}

I basically just added the somevalue as $leafValue and moved the base case around so that it would add the leafValue instead of a blank array at the end.

This results in:

Array
(
    [path] => Array
        (
            [to] => Array
                (
                    [directory] => Array
                        (
                            [file1] => someValue
                        )
                )
            [directory] => Array
                (
                    [file2] => someValue
                )
        )
    [path2] => Array
        (
            [dir] => Array
                (
                    [file3] => someValue
                    [file4] => someValue
                )
        )
)

Thanks a lot!

Chris
  • 4,277
  • 7
  • 40
  • 55
0

It can be done without recursion

$path = array(
'path/to/directory/file1',
'path/directory/file2',
'path2/dir/file3',
'path2/dir/file4');

$arr = [];
$someValue = 'someValue';

foreach ( $path as $p ) {
    $segments = explode('/', $p);
    $str = '';
    $p = &$arr;
    foreach ( $segments as $s ) {
        if (! isset($p[$s] ) ) $p[$s] = array();
        $p = &$p[$s];
    }
    $p = $someValue;
}

print_r($arr);
splash58
  • 26,043
  • 3
  • 22
  • 34