Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encode nested array to proper json without array indexes

Tags:

json

arrays

php

I have a sample 2d $tasks array which describes a nested structure :

Array
(
    [14] => Array
        (
            [Id] => 14
            [parentId] => null
            [Name] => T1
        )

    [40] => Array
        (
            [Id] => 40
            [parentId] => null
            [Name] => T5
        )

    [41] => Array
        (
            [Id] => 41
            [parentId] => null
            [Name] => T4
        )

    [22] => Array
        (
            [Id] => 22
            [parentId] => 14
            [Name] => T2
        )

    [43] => Array
        (
            [Id] => 43
            [parentId] => 22
            [Name] => T2 child
        )

    [42] => Array
        (
            [Id] => 42
            [parentId] => 14
            [Name] => T3
        )

)

Using the code below I'm transforming this to a proper tree structure :

$sortedArray = array();
// get first level
foreach($tasks as $k => $v){
    if($v['parentId'] == 'null'){
        $sortedArray[$k] = $v;
        unset($tasks[$k]);
    }
}
// sort parents
asort($sortedArray);

function getChildren(array & $a1, array & $a2){
    foreach($a1 as $k => $v){
        findChildren($v, $a2, $k);      
    }
}

function findChildren($rec1, array & $a2, $key){

    foreach($a2 as $k => $v){
        if($rec1['parentId'] == $v['Id']){
            $a2[$k]['children'][$rec1['Id']] = $rec1;
            unset($tasks[$key]);
        } else {
            if (isset($v['children'])){
                findChildren($rec1, $a2[$k]['children'], $key);
            }
        }
    }
}

findChildren($tasks, $sortedArray);

And tho output $sortedArray after running this code looks as follows :

Array
(
    [14] => Array
        (
            [Id] => 14
            [parentId] => null
            [Name] => T1
            [children] => Array
                (
                    [22] => Array
                        (
                            [Id] => 22
                            [parentId] => 14
                            [Name] => T2
                            [children] => Array
                                (
                                    [43] => Array
                                        (
                                            [Id] => 43
                                            [parentId] => 22
                                            [Name] => T2 child
                                        )

                                )

                        )

                    [42] => Array
                        (
                            [Id] => 42
                            [parentId] => 14
                            [Name] => T3
                        )

                )

        )

    [40] => Array
        (
            [Id] => 40
            [parentId] => null
            [Name] => T5
        )

    [41] => Array
        (
            [Id] => 41
            [parentId] => null
            [Name] => T4
        )

)

The problem is, that after calling json_encode on this output array in it's current state I'm getting :

{"14":{"Id":"14","parentId":"null"...

so all nested arrays are inserted with their indexes. I know I can fix the first level using array_values. But is there any simple way of doing this for all levels ? Without it I end up with 'children' being not an array but object which is not satisfying for me.

like image 236
mike_hornbeck Avatar asked May 25 '26 05:05

mike_hornbeck


2 Answers

The code isn't present in your post, but $tasks was created as an associative array. In your example you also iterate through $tasks as you would an associative array:

foreach($tasks as $k => $v){
    ...
}

You need to add children to $tasks as you would with a numeric array; the difference is this:

//associative array
$test = array();
$test["43"] = "hello";
$test["40"] = "hello1";
$test["23"] = "hello2";
print_r($test);

//numeric array
$testb = array(); 
$testb[] = "hello";
$testb[] = "hello1";
$testb[] = "hello2";
print_r($testb);

Live example: http://codepad.org/tsOhX88h

With the numeric array, the top level index (e.g., 14) you've cited as the problem {"14":{"Id":"14","parentId":"null"... is no longer present.

As a simple final step, use this code to push the items from the associative array on to a new numeric array:

$finalArray = array();
foreach ($sortedArray as $key=>$val ){
    $finalArray[] = $sortedArray[$key];
}
print_r($finalArray);

Live example: http://codepad.org/uSGSr1DC

Or you could do it in one shot with array_values:

$finalArray = array();
$finalArray = array_values($sortedArray);
print_r($finalArray);

Live example: http://codepad.org/D7uBSRr8

like image 78
Elliot B. Avatar answered May 27 '26 17:05

Elliot B.


You did not include your json_encode call, if you happened to do it like this...

json_encode(array_values($sortedArray), JSON_FORCE_OBJECT);

then the force will put the numeric indexes in anyway. Not sure if this will help you but it might help someone else who's seeing the same problem.

like image 21
sirhacksalot Avatar answered May 27 '26 18:05

sirhacksalot