2

So I'm suppose to build a multidimensional array dynamically from a text file, and everything works perfectly except that the numeric keys are screwing me over...

The text file looks something like this:

a=1
b.c=2
b.d.0.e=3
b.d.0.f=4
b.d.1.e=5
b.d.1.f=6

As the array_merge_recursive doesn't work with numeric keys, the output is like:

array(2) { 
 ["a"]=>  
 string(3) "1" 
 ["b"]=>  
 array(2) { 
  ["c"]=>  
  string(3) "2" 
  ["d"]=>  
  array(4) { 
   [0]=>  
   array(1) { 
    ["e"]=>  
    string(9) "3" 
   } 
   [1]=>  
   array(1) { 
    ["f"]=>  
    string(4) "4" 
   } 
   [2]=>  array(1) { 
    ["e"]=>  
    string(8) "5" 
   } 
   [3]=>  
   array(1) { 
    ["f"]=>  
    string(9) "6" 
 }}}}

Is there any easy solution to make the output like...?

array(2) { 
 ["a"]=>  
 string(3) "1" 
 ["b"]=>  
 array(2) {
  ["c"]=>  
  string(3) "2" 
  ["d"]=>  
  array(2) { 
   [0]=>  
   array(2) { 
    ["e"]=>  
    string(9) "3" 
    ["f"]=>  
    string(4) "4"  
   } 
   [1]=>  
   array(3) { 
    ["e"]=>  
    string(9) "5"
    ["f"]=>  
    string(4) "6"
}}}}

Thanks

1
  • Any of the solutions in the answers will work, but I'd suggest to whomever is storing the data like this that it be done more appropriately (for example, using json strings). Commented Jan 12, 2010 at 15:15

3 Answers 3

3

You could break each bit into its components and build up the array one step at a time.

$path = "b.d.0.e";
$val = 3;
$output = array();

$parts = explode(".", $path);

// store a pointer to where we currently are in the array.
$curr =& $output;

// loop through up to the second last $part
for ($i = 0, $l = count($parts); $i < $l - 1; ++$i) {
    $part = $parts[$i];

    // convert numeric strings into integers
    if (is_numeric($part)) {
        $part = (int) $part;
    }

    // if we haven't visited here before, make an array
    if (!isset($curr[$part])) {
        $curr[$part] = array();
    }

    // jump to the next step
    $curr =& $curr[$part];
}

// finally set the value
$curr[$parts[$l - 1]] = $val;

My output, using the same input as yours:

Array (
    [a] => 1
    [b] => Array (
        [c] => 2
        [d] => Array (
            [0] => Array (
                [e] => 3
                [f] => 4
            )
            [1] => Array (
                [g] => 5
                [h] => 6
            )
        )
    )
)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for a good answer :) The if(is_numeric) isn't needed though, I think it already interprets the var as an int.
0

Or you could use eval():

$raw_data = file($txt_file, FILE_IGNORE_NEW_LINES);
foreach ($raw_data as $line) {
    list($keys, $value) = explode('=', $line);
    $keys = explode('.', $keys);
    $arr_str = '$result';
    foreach ($keys as $key) {
        if (ctype_digit($key)) {
            $arr_str .= "[" . $key . "]";
        } else {
            $arr_str .= "['" . $key . "']";
        }
    }
    eval($arr_str . ' = $value;');
}

print_r($result);

Comments

0

I know this is an old one, but the best solution I have found is to use array_replace_recursive. It will achieve what you are looking to do:

$start = array(
   "600" => array("total" => 100),
   "700" => array("total" => 200)
);

$finish = array(
  "600" => array("average" => 25),
  "700" => array("average" => 50)
);

$out = array_replace_recursive($start,$finish);
var_dump($out):

array(2) {
  [600]=>
  array(2) {
    ["total"]=>
    int(100)
    ["average"]=>
    int(25)
  }
  [700]=>
  array(2) {
    ["total"]=>
    int(200)
    ["average"]=>
    int(50)
  }
}

Comments

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.