0

I need to convert a hierarchical multidimensional array into a 2d array by recursively traversing each subset of data and push them into a result array.

Input:

$multi = [
    [
        'case_code_id' => 1,
        'parent_id' => 0,
        'case_code' => 'Main A',
        'sub_codes' => [
            [
                'case_code_id' => 3,
                'parent_id' => 1,
                'case_code' => 'Sub A',
                'sub_codes' => [
                    [
                        'case_code_id' => 5,
                        'parent_id' => 3,
                        'case_code' => 'Sub Sub A',
                        'sub_codes' => []
                    ]
                ]
            ],
            [
                'case_code_id' => 4,
                'parent_id' => 1,
                'case_code' => 'Sub B',
                'sub_codes' => []
            ]
        ]
    ],
    [
        'case_code_id' => 2,
        'parent_id' => 0,
        'case_code' => 'Main B',
        'sub_codes' => []
    ]
]

Desired result:

Array
(
    [0] => Array
    (
        [case_code_id] => 1
        [parent_id] => 0
        [case_code] => Main A
    )
    [1] => Array 
    (
        [case_code_id] => 3
        [parent_id] => 1
        [case_code] => Sub A
    )
    [2] => Array
    (
        [case_code_id] => 5
        [parent_id] => 3
        [case_code] => Sub Sub A
    )
    [3] => Array
    (
        [case_code_id] => 4
        [parent_id] => 1
        [case_code] => Sub B
    )
    [4] => Array
    (
        [case_code_id] => 2
        [parent_id] => 0
        [case_code] => Main B
    )
)

I have tried several loops but nothing returns the full array.

Here is what I have for my loop:

public function array_flatten($array, $list = array()) {
    for ($i = 0; $i < count($array); $i++) {
        $results[] = array(
            'case_code_id' => $array[$i]['case_code_id'],
            'case_code' => $array[$i]['case_code'],
            'parent_id' => $array[$i]['parent_id']
        );
        if (count($array[$i]['sub_codes']) > 0) {
            $this->array_flatten($array[$i]['sub_codes'], $results);
        } else {
            $results[] = $array[$i];
        }
    }
    return $results;
}

And I'm calling it like this: ($multi contains the multidimensional array)

$flat = $this->array_flatten($multi); 

The variable $multi is created from this function:

public function build_case_code_tree(array $elements, $parentId = 0) {
    $branch = array();
    foreach ($elements as $element) {
        if ($element['parent_id'] == $parentId) {
            $children = $this->build_case_code_tree($elements, $element['case_code_id']);
            $element['sub_codes'] = $children;
            $branch[] = $element;
        }
    }
    return $branch;
}

Any thoughts?

4
  • Possible duplicate of How to "flatten" a multi-dimensional array to simple one in PHP? Commented Sep 25, 2018 at 19:45
  • 1
    The suggested post did not produce the results I'm looking for. This is what the output looked like Array ( [0] => 1 [1] => 0 [2] => Main A [3] => 3 [4] => 1 [5] => Sub A [6] => 5 [7] => 3 [8] => Sub Sub A [9] => 4 [10] => 1 [11] => Sub B [12] => 2 [13] => 0 [14] => Main B ) Commented Sep 25, 2018 at 19:47
  • It would be super helpful if you could provide the initiation of $multi for us instead of expecting us to mock up our own data based on your print_r(). It generally helps you to get relevant and working answers when you provide an easy way for us to test the sample data... Commented Sep 25, 2018 at 20:11
  • I added the function the generates the multi array. Commented Sep 25, 2018 at 20:33

3 Answers 3

1
function array_flatten($a, $flat = []) {
    $entry = [];
    foreach ($a as $key => $el) {
        if (is_array($el)) {
            $flat = array_flatten($el, $flat);
        } else {
            $entry[$key] = $el;
        }
    }
    if (!empty($entry)) {
        $flat[] = $entry;
    }
    return $flat;
}
print_r(array_flatten($multi));
Sign up to request clarification or add additional context in comments.

Comments

0

You're not using $list anywhere in the code, and nothing is passed by reference. You're close, but your function should use $list in the place of $results, and it should receive $list by reference and modifying it in place instead of returning it.

Something like this (untested though):

function array_flatten($array,&$list=array()){
    for ($i=0;$i<count($array);$i++) {
        $list[] = array(
            'case_code_id'=>$array[$i]['case_code_id'],
            'case_code'=>$array[$i]['case_code'],
            'parent_id'=>$array[$i]['parent_id']
        );
        if (count($array[$i]['sub_codes']) > 0) {
            $this->array_flatten($array[$i]['sub_codes'],$list);
        } else {
            $list[] = $array[$i];
        }
    }
}

And calling it like this:

$flat = Array();
$this->array_flatten($multi, $flat);
// Result is inside $flat now

1 Comment

I updated the code, but not getting any results. Should there be a return?
0

As you recursively traverse all levels and iterate each subset, temporarily hold the sub_code value, then remove the sub_code element from the subset. Push the trimmed subset into the result array and also feed the cached sub_code data into a recursive function call.

If the child was empty, then an empty array will be returned. If an empty array is "spread" as a parameter of array_push(), then nothing will be added to the array. Because the custom function call only returns a linear array of subsets, using the spread operator inside of array_push() means that recursive calls will never create unwanted depth.

Code: (Demo)

function flatten(array $array): array
{
    $result = [];
    foreach ($array as $v) {
        $subCode = $v['sub_codes'];
        unset($v['sub_codes']);
        array_push(
            $result,
            $v,
            ...flatten($subCode)
        );
        
    }
    return $result;
}

var_export(flatten($array));

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.