phparrayssortingusortksort

Sort associative array by key like filenames on a computer


I have following structure:

$arr = [
    'children' => [
        'align.php' => [],
        'default.php' => [],
        'test.php' => [],
        'default-2.php' => [],
    ]
]

Currently I am using

ksort($arr['children'])

and it sorts it like that:

$arr = [
    'children' => [
        'align.php' => [],
        'default-2.php' => [],
        'default.php' => [],
        'test.php' => [],
    ]
]

However, I need the array to be in this order:

$arr = [
    'children' => [
        'align.php' => [],
        'default.php' => [],
        'default-2.php' => [],
        'test.php' => [],
    ]
]

I've tried the NATURAL_SORT flag, but that didn't work. What other options are there?


Solution

  • You can extract the file names using the pathinfo function, and then compare them in the callback function in the uksort function.

    uksort($arr['children'], function($a, $b){
        $a = pathinfo($a);
        $b = pathinfo($b);
        return $a['filename'] == $b['filename'] ? 
            $a['basename'] <=> $b['basename'] :
            $a['filename'] <=> $b['filename'];
    
    });
    

    fiddle

    A more complex sorting of file names with multiple dots is solved, for example, like this

    /* Example:
        a
        a.class
        a.class.php
        a.class.php-1
        a.class-1.php
        a.class-1.php-1
        a-1
        a-1.class.php
        a-1.class-1
        a-1.class-1.php-1
    */
    
    uksort($arr['children'], function($a, $b){
        $a = explode('.', $a);
        $b = explode('.', $b);
        $s = '';
        $i = 0;
        while (isset($a[$i]) && isset($b[$i]) && $a[$i] == $b[$i]) {
            $s .= $a[$i++] . '.'; 
        }
        return $s . ($a[$i] ?? '') <=> $s . ($b[$i] ?? '');
    });
    

    fiddle