Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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

share|improve this question
    
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). –  GZipp Jan 12 '10 at 15:15

3 Answers 3

up vote 2 down vote accepted

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
            )
        )
    )
)
share|improve this answer
    
Thanks for a good answer :) The if(is_numeric) isn't needed though, I think it already interprets the var as an int. –  per_pilot Jan 12 '10 at 15:40

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);
share|improve this answer

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)
  }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.