1

We have an array with the following values:

$a = array("a", "a.b", "a.b.c", "X", "X.Y", "X.Y.Z");

And the goal is, to make modify the first array into the following structure:

$a = array(
     "a" => array(
         "b" => array(
             "c" => array(),
         ),
     ),
     "X" => array(
         "Y" => array(
             "Z" => array(),
         ),
     ),
);

Why i am asking? On of my customer has a table for shop categories. And these categories are in one column (simplified!):

 +-----------------------+
 |id |       name        |
 +---|-------------------+
 | 4 | A                 |
 | 5 | A.B               |
 | 6 | A.B.C             |
 | 7 | X                 |
 | 8 | X.Y               |
 | 9 | X.Y.Z             |
 +-----------------------+

How can i do this with PHP?

EDIT:

My current "solution / trys"

<?php

$arr = array(
    "a",
    "a.b",
    "a.b.c",
    "x",
    "x.y",
    "x.y.z",
);

$container = array();
$updateMe = array();

foreach($arr as $key => $value) {
    $cleanName = explode(".", $value);

    foreach($cleanName as $keyArray => $valueArray) {
        for($c = 0;$c<$keyArray+1;$c++) {
            $updateMe[$cleanName[$c]] = array();
        }


    } 

    $container[$cleanName[0]] = $updateMe;
    unset($updateMe);
}

echo "<pre>";
var_dump($container);
echo "===\r\n";

My output:

array(2) {
  ["a"]=>
  array(3) {
    ["a"]=>
    array(0) {
    }
    ["b"]=>
    array(0) {
    }
    ["c"]=>
    array(0) {
    }
  }
  ["x"]=>
  array(3) {
    ["x"]=>
    array(0) {
    }
    ["y"]=>
    array(0) {
    }
    ["z"]=>
    array(0) {
    }
  }
}
===

SOLUTION

<?php

$arr = array(
    "a",
    "a.b",
    "a.b.c",
    "x",
    "x.y",
    "x.y.z",
);

$array = array();
$test = array();

foreach($arr as $key => $text) {
    $array = array();
    foreach(array_reverse(explode('.', $text)) as $key) $array = array($key => $array);

    $test[] = $array;
}

echo "<pre>";
var_dump($test);
echo "===\r\n";
12

4 Answers 4

2

I like using references in PHP. This might not be the best solution, but it seems to work.

<?php
$arr = array(
    "a",
    "a.b",
    "a.b.c",
    "x",
    "x.y",
    "x.y.z",
);

$output = array();

foreach($arr as $path){
    // Create a reference to the array
    // As we go deeper into the path we will move this reference down
    $setArray =& $output;

    foreach(explode('.', $path) as $key){
        // If this key does not exist, create it
        if(!isset($setArray[$key])){
            $setArray[$key] = array();
        }

        // Move the reference down one level,
        // so that the next iteration will create
        // the key at the right level
        $setArray =& $setArray[$key];
    }
}

// Destroy the reference, so that we don't accidently write to it later
unset($setArray);

var_dump($output);
Sign up to request clarification or add additional context in comments.

1 Comment

Another great answer! The advantage for this solution is, that there is no duplicated content / duplicated layers / elements inside the array!
1

You can use the accepted answer from this question, or this answer from the same question to get a good starting point (I'll use the second answer because it's shorter in this example).

$out = array();
foreach ($a as $string) {
    $array = array();
    foreach(array_reverse(explode('.', $string)) as $key) {
        $array = array($key => $array);
    }
    $out[] = $array;
}

This will give you a numeric key based array, so then you can shift off the first level of the array using an answer from this question:

$out = call_user_func_array('array_merge', $out);

And your result:

Array
(
    [a] => Array
        (
            [b] => Array
                (
                    [c] => Array
                        (
                        )

                )

        )

    [X] => Array
        (
            [Y] => Array
                (
                    [Z] => Array
                        (
                        )

                )

        )

)

1 Comment

That's the snippet i looked for! Thanks alot!
0

This should work for you:

<?php

    $a = array("a", "a.b", "a.b.c", "1", "1.2", "1.2.3");
    $results = array();

    function stringToArray($path) {

        $pos = strpos($path, ".");

        if ($pos === false)
            return array($path => "");

        $key = substr($path, 0, $pos);
        $path = substr($path, $pos + 1);

        return array(
            $key => stringToArray($path)
        );

    }

    foreach($a as $k => $v) {
        if(substr_count(implode(", ", $a), $v) == 1)
            $results[] = stringToArray($v);
    }

    $results = call_user_func_array('array_merge', $results);
    print_R($results);

?>

Output:

Array ( [a] => Array ( [b] => Array ( [c] => ) ) [0] => Array ( [2] => Array ( [3] => ) ) )

Comments

0

just tricky one

  $a = array("a", "a.b", "a.b.c", "X", "X.Y", "X.Y.Z");

    $res = array();
    foreach ($a as $str) {
        $str = str_replace('.','"]["',$str);
        $tricky = '$res["'.$str.'"]';
        eval ($tricky.' = array();');
};

1 Comment

Using eval for this is bad news.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.