Skip to content
Advertisement

How to ‘flatten’ a multi dimensional array of unknown depth and length AND record it’s parent-child relations? [closed]

I have a PHP array that looks like this:

Array
(
    [0] => Array
        (
            [id] => 2
            [name] => Item2
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [name] => Item1
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 5
                                            [name] => Item5
                                        )
                                )
                        )
                    [1] => Array
                        (
                            [id] => 4
                            [name] => Item4
                        )
                )
        )
    [1] => Array
        (
            [id] => 3
            [name] => Item3
        )
)

It has unknown (unpredictable) depth and length. Any item on any level may or may not have children. It has been created from an xml file that contains product groups. I would like to convert it to an array that contains arrays of three elements: id, name, and parent id:

[0] => array('id' => '2', 'name' => 'Item2', 'parent' => 0),
[1] => array('id' => '1', 'name' => 'Item1', 'parent' => 2),
[2] => array('id' => '4', 'name' => 'Item4', 'parent' => 2) etc.

How can I do it? Thank you!

Advertisement

Answer

This can be achieved with a recursive function that pushes all the items from a given level of the array, then calls itself for any children arrays:

function list_items($array, $parent = 0) {
    $output = array();
    foreach ($array as $arr) {
        $output[] = array('id' => $arr['id'], 'name' => $arr['name'], 'parent' => $parent);
        if (is_array($arr['children'] ?? NULL)) {
            $output = array_merge($output, list_items($arr['children'], $arr['id']));
        }
    }
    return $output;
}

$items = list_items($array);

Output (for my slightly expanded data):

Array
(
    [0] => Array
        (
            [id] => 2
            [name] => Item2
            [parent] => 0
        )
    [1] => Array
        (
            [id] => 1
            [name] => Item1
            [parent] => 2
        )
    [2] => Array
        (
            [id] => 5
            [name] => Item5
            [parent] => 1
        )
    [3] => Array
        (
            [id] => 4
            [name] => Item4
            [parent] => 2
        )
    [4] => Array
        (
            [id] => 3
            [name] => Item3
            [parent] => 0
        )
)

Demo on 3v4l.org

Update

It turns out that there is an inconsistency in the array structure; when there is only one child, only the child value is stored rather than a single element array. This can be dealt with by checking the the array to see if the id (Ид) element is set, and if it is, pushing the array one level deeper before processing:

function list_items($array, $parent = 0) {
    $output = array();
    if (isset($array['Ид'])) {
        $array = array($array);
    }
    foreach ($array as $arr) {
        if (!is_array($arr)) echo $arr;
        $output[] = array('id' => $arr['Ид'], 'name' => $arr['Наименование'], 'parent' => $parent);
        if (is_array($arr['Группы']['Группа'] ?? NULL)) {
            $output = array_merge($output, list_items($arr['Группы']['Группа'], $arr['Ид']));
        }
    }
    return $output;
}

$items = list_items($array);
print_r($items);

Demo on 3v4l.org

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement