24

I am having a hard time trying recursively sort a multidimensional array on its keys. I tried with usort(), but with no success.

Sample data:

[
    'first_level' => [
        'dir_3' => [
            'subdir_1' => [
                'file_2.mp4' => (object) [
                    'name' => 'file_2.mp4',
                ],
                'file_1.mp4' => (object) [
                    'name' => 'file_1.mp4',
                ],
            ],
        ],
        'dir_1' => [
            'subdir_2' => [
                'file_6.mp4' => (object) [
                    'name' => 'file_6.mp4',
                ],
                'file_9.mp4' => (object) [
                    'name' => 'file_9.mp4',
                ],
                'file_7.mp4' => (object) [
                    'name' => 'file_7.mp4',
                ],
            ],
            'subdir_1' => [
                'file_8.mp4' => (object) [
                    'name' => 'file_8.mp4',
                ],
            ],
        ],
    ],
]

Desired result:

[
    'first_level' => [
        'dir_1' => [
            'subdir_1' => [
                'file_8.mp4' => (object) [
                    'name' => 'file_8.mp4',
                ],
            ],
            'subdir_2' => [
                'file_6.mp4' => (object) [
                    'name' => 'file_6.mp4',
                ],
                'file_7.mp4' => (object) [
                    'name' => 'file_7.mp4',
                ],
                'file_9.mp4' => (object) [
                    'name' => 'file_9.mp4',
                ],
            ],
        ],
        'dir_3' => [
            'subdir_1' => [
                'file_1.mp4' => (object) [
                    'name' => 'file_1.mp4',
                ],
                'file_2.mp4' => (object) [
                    'name' => 'file_2.mp4',
                ],
            ],
        ],
    ],
]

4 Answers 4

41

Use a recursive function to call ksort on the current level and all deeper subarrays.

function recur_ksort(&$array) {
    foreach ($array as &$value) {
        if (is_array($value))
            recur_ksort($value);
     }
     ksort($array);
}

recur_ksort($array);
var_export($array);

Demo: https://3v4l.org/Xede5

Sign up to request clarification or add additional context in comments.

1 Comment

This answer made me spot a silly mistake in my own code. :o I came up with some very similar code on my own, but I forgot the & before &$value, so I was breaking my head why only my first level was getting sorted. Thanks for unwittingly helping me. ;)
6

You need to use ksort with recursion. Demo

function recursive_ksort(&$array) {
    foreach ($array as &$v) {
        if (is_array($v)) {
            recursive_ksort($v);
        }
    }
    ksort($array);
}

recursive_ksort($array);
var_export($array);

Comments

4
function ksort_recursive(&$array)
{
    if (is_array($array)) {
        ksort($array);
        array_walk($array, 'ksort_recursive');
    }
}

It is not necessary within the recursive function to return ksort() -- this would return the unwanted success boolean value from ksort() anyhow.

Note that this function does not throw "Warning: ksort() expects parameter 1 to be array" when given a non-array - this matches my requirements but perhaps not yours. Demo: https://3v4l.org/bogAU

Comments

1

It is fair to assume that you'd like your data ti be sorted "naturally" -- meaning that the number portion of the directory and file names should be sorted numerically instead of as simple strings. Without sorting naturally, dir_10 will be moved in front of dir_2 because when comparing the 5th character of the two strings, 1 is less than 2.

Code: (Demo)

function nat_ksort_r(&$data): void
{
    if (is_array($data)) {
        ksort($data, SORT_NATURAL);
        array_walk($data, __METHOD__);
    }
}

nat_ksort_r($array);
var_export($array);
  • For natural sorting, apply the SORT_NATURAL flag to the ksort() call.
  • For simpler maintenance of the recursive function, recall the function using the __METHOD__ magic constant. This makes one less place to change nat_ksort_r() if you wish to call the custom function something else.
  • This recursive function does not return any data; it modifies the original array by reference.
  • The lowest level contains objects and this data does not get sorted by the function.

The above function can also use a classic loop instead of a functional iterator. (Demo)

function nat_ksort_r(&$data): void
{
    if (is_array($data)) {
        ksort($data, SORT_NATURAL);
        foreach ($data as &$item) {
            (__METHOD__)($item);
        }
    }
}

nat_ksort_r($array);
var_export($array);

You can even write the code in a completely anonymous fashion. Demo

$nat_ksort_r = function(&$data) use (&$nat_ksort_r) {
    if (is_array($data)) {
        ksort($data, SORT_NATURAL);
        foreach ($data as &$item) {
            $nat_ksort_r($item);
        }
    }
};
$nat_ksort_r($array);
var_export($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.